标签:
进程是程序级并发,线程是函数级并发。
三种基本的构造并发程序的方法:
构造并发程序最简单的方法就是用进程。
使用大家都很熟悉的函数例如:
关于在父、子进程间共享状态信息:共享文件表,但不共享用户地址空间。
进程又独立的地址空间既是优点又是缺点:
就是使用select函数要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序。
select函数处理类型为fd_set的集合,也叫做描述符集合。
select函数有两个输入:一个称为读集合的描述符集合和该妒忌和该读集合的基数(n)(实际上是任何描述符集合的最大基数)。select函数会一直阻塞,直到读集合中至少有一个描述符准备好可以读。当且仅当一个从该描述符读取一个字节的请求不会阻塞时,描述符K就表示准备好可以读了。
作为一个副作用,select修改了参数fdset指向的fd_set,指明读集合中一个称为准备好集合的子集。函数返回的值指明了准备好的集合的基数。由于这个副作用,我们必须在每次调用select函数时都更新集合。
I/O多路复用可以用作并发事件驱动程序的基础。
服务器使用I/O多路复用,借助select函数检测输入事件的发生。
线程就是运行在进程上下文中的逻辑流。
基于线程的逻辑流结合了基于进程和基于I/O多路复用的流的特性。
每个进程开始生命周期时都是单一线程,这个线程称为主线程。在某一时刻,主线程创建一个对等线程,从这个时间点开始,两个线程就并发地运行。
在一些重要的方面,线程执行是不同于进程的,因为一个线程的上下文比一个进程的上下文小很多,线程的上下文切换比进程的上下文快得多。
另一个不同就是线程不像进程那样,不是按照严格的父子层次来组织的。和一个进程相关的线程组成一个对等(线程)池,独立于其他线程创建的线程。
主线程总是进程中第一个运行的线程。对等(线程)池的概念的主要影响是,一个线程可以杀死它的任何对等线程,或者等待它的任意对等线程终止。另外,每个对等线程都能读写相同的共享数据。
Posix线程是C程序中处理线程的一个标准接口。基本用法是:
这里需要提到一个万能函数的概念。
万能函数:
void func(void parameter)
typedef void (uf)(void para)
即,输入的是指针,指向真正想要传到函数里的数据,如果只有一个就直接让指针指向这个数据,如果是很多就将它们放到一个结构体中,让指针指向这个结构体。后面这个方法就是万能函数的使用思想。
线程例程也是这样的。
创建线程:
终止线程:
回收已终止线程的资源:
分离进程:
初始化线程:
每个线程都有它自己独自的线程上下文,包括:
线程ID
栈
栈指针
程序计数器
条件码
通用目的寄存器值。
每个线程和其他线程一起共享进程上下文的剩余部分。
寄存器是从不共享的,而虚拟存储器总是共享的。
线程化的c程序中变量根据它们的存储器类型被映射到虚拟存储器:
全局变量
本地自动变量(不共享)
本地静态变量
共享变量引入了同步错误。
进度图:
轨迹线示例:
临界区(不安全区):
并行程序的加速比通常定义为:
其中,p为处理器核的数量,T为在p个核上的运行时间。
定义四个(不相交的)线程不安全函数类:
当一个程序的正确性依赖于一个线程要在另一个线程到达y点之前到达他的控制流x点时,就会发生竞争。
为消除竞争,我么可以动态地为每个整数ID分配一个独立的块,并且传递给线程例程一个指向这个块的指针。
死锁:一组线程被阻塞了,等待一个永远也不会为真的条件。
互斥锁加锁顺序规则:如果对于程序中每对互斥锁(s,t),给所有的锁分配一个全序,每个线程按照这个顺序来请求锁,并且按照逆序来释放,这个程序就是无死锁的。
1、深入理解计算机系统课本
2、百度百科
3、http://www.cnblogs.com/tymjava/p/5024202.html谈愈敏同学博客
标签:
原文地址:http://www.cnblogs.com/hw00332012/p/5024276.html