标签:
进程是程序级并发,线程是函数级并发。
三种基本的构造并发程序的方法:
构造并发程序最简单的方法就是用进程。
使用大家都很熟悉的函数例如:
关于在父、子进程间共享状态信息:共享文件表,但不共享用户地址空间。
进程又独立的地址空间既是优点又是缺点:
就是使用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)
即,输入的是指针,指向真正想要传到函数里的数据,如果只有一个就直接让指针指向这个数据,如果是很多就将它们放到一个结构体中,让指针指向这个结构体。后面这个方法就是万能函数的使用思想。
线程例程也是这样的。
创建线程:
终止线程:
回收已终止线程的资源:
分离进程:
初始化线程:
一个变量是共享的,当且仅当多个线程引用这个变量的某个实例。
一组并发线程运行在一个进程的上下文中。
每个线程都有它自己的线程上下文:
线程化的C程序中变量根据他们的存储类型被映射到虚拟存储器:
变量v是共享的——当且仅当它的一个实例被一个以上的线程引用。
共享变量十分方便,但也引入了同步错误的可能性。
这里有个关键点:一般而言,你没有办法预测操作系统是否将为你的线程选择一个正确的顺序。
进度图:
进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线,原点对应于没有任何线程完成一条指令的初始状态。
当n=2时,状态比较简单,是比较熟悉的二维坐标图,横纵坐标各代表一个线程,而转换被表示为有向边
转换规则:
而一个程序的执行历史被模型化为状态空间中的一条轨迹线。
标签:
原文地址:http://www.cnblogs.com/disturbia/p/5024066.html