那么马路中间白色虚线分隔开来的各个车道就是进程中的各个【线程】了。
①这些线程(车道)共享了进程(道路)的公共资源(土地资源)。
②这些线程(车道)必须依赖于进程(道路),也就是说,线程不能脱离于进程而存在(就像离开了道路,车道也就没有意义了)。
③这些线程(车道)之间可以并发执行(各个车道你走你的,我走我的),也可以互相同步(某些车道在交通灯亮时禁止继续前行或转弯,必须等待其它车道的车辆通行完毕)。
④这些线程(车道)之间依靠代码逻辑(交通灯)来控制运行,一旦代码逻辑控制有误(死锁,多个线程同时竞争唯一资源),那么线程将陷入混乱,无序之中。
⑤这些线程(车道)之间谁先运行是未知的,只有在线程刚好被分配到CPU时间片(交通灯变化)的那一刻才能知道
注:
由于用于互斥的信号量sem与所有的并发进程有关,所以称之为公有信号量。公有信号量的值反映了公有资源的数量。只要把临界区置于P(sem)和V(sem)之间,即可实现进程间的互斥。就象火车中的每节车厢只有一个卫生间,该车厢的所有旅客共享这个公有资源:卫生间,所以旅客间必须互斥进入卫生间,只要把卫生间放在P(sem)和V(sem)之间,就可以到达互斥的效果。
如何用P V 原语实现进程间的互斥与同步 如何用P V 原语实现进程间的互斥与同步2010-07-29 20:03 导读: PV 原语的含义 P 操作和V 操作是不可中断的程序段,称为原语。PV 原语及信号量的概念都是由荷兰科学家E.W.Dijkstra 提出的。信号量sem 是一整数,sem 大于等于零时代表可供并发进程使用的资源实体数,但sem 小于零时则表示正在等待使用临界区的进程数。 P 原语操作的动作是: (1)sem 减1; (2)若sem 减1 后仍大于或等于零,则进程继续执行; (3)若sem 减1 后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。 V 原语操作的动作是: (1)sem 加1; (2)若相加结果大于零,则进程继续执行; (3)若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。 PV 操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV 原语执行期间不允许有中断的发生。 P 原语:P 是荷兰语Proberen(测试)的首字母。为阻塞原语,负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞; V 原语:V 是荷兰语Verhogen(增加)的首字母。为唤醒原语,负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。 具体PV 原语对信号量的操作可以分为三种情况: 1)把信号量视为一个加锁标志位,实现对一个共享变量的互斥访问。 实现过程: P(mutex);//mutex 的初始值为1 访问该共享数据; V(mutex); 非临界区 2)把信号量视为是某种类型的共享资源的剩余个数,实现对一类共享资源的访问。 实现过程: P(resource);//resource 的初始值为该资源的个数N 使用该资源; V(resource);非临界区 3)把信号量作为进程间的同步工具 实现过程: 临界区C1; P(S); V(S); 临界区C2; 用PV 原语实现进程的互斥 由于用于互斥的信号量sem 与所有的并发进程有关,所以称之为公有信号量。公有信号量的值反映了公有资源的数量。只要把临界区置于P(sem)和V (sem)之间,即可实现进程间的互斥。就象火车中的每节车厢只有一个卫生间,该车厢的所有旅客共享这个公有资源:卫生间,所以旅客间必须互斥进入卫生 间,只要把卫生间放在P(sem)和V(sem)之间,就可以到达互斥的效果。以下例子说明进程的互斥实现。 例1 生产围棋的工人不小心把相等数量的黑子和白子混装载一个箱子里,现要用自动分拣系统把黑子和白子分开,该系统由两个并发执行的进程组成,功能如下: (1)进程A 专门拣黑子,进程B 专门拣白子; (2)每个进程每次只拣一个子,当一个进程在拣子时不允许另一个进程去拣子; 分析: 第一步:确定进程间的关系。由功能(2)可知进程之间是互斥的关系。 第二步:确定信号量及其值。由于进程A 和进程B 要互斥进入箱子去拣棋子,箱子是两个进程的公有资源,所以设置一个信号量s,其值取决于公有资源的数目,由于箱子只有一个,s 的初值就设为1。 实现: begin s:semaphore; s:=1; cobegin process A begin L1: P(s); 拣黑子; V(s); goto L1; end; process B begin L2:P(s); 拣白子; V(s); goto L2; end; coend; end; 判断进程间是否互斥,关键是看进程间是否共享某一公有资源,一个公有资源与一个信号量相对应。确定信号量的值是一个关键点,它代表了可用资源实体数。如下实例: 例2 某车站售票厅,任何时刻最多可容纳20 名购票者进入,当售票厅中少于 20 名购票者时,厅外的购票者可立即进入,否则需要在外面等待。每个购票者可看成一个进程。 分析:第一步:确定进程间的关系。售票厅是各进程共享的公有资源,当售票厅中多于20 名购票者时,厅外的购票者需要在外面等待。所以进程间是互斥的关 系。第二步:确定信号量及其值。只有一个公有资源:售票厅,所以设置一个信号量s。售票厅最多容纳20 个进程,即可用资源实体数为20,s 的初值就设为 20。 实现: begin s:semaphore; s:=20; cobegin process PI(I=1,2,…) begin P(s); 进入售票厅; 购票; 退出; V(s); end; coend 当购票者进入售票厅前要执行P(s)操作,执行后若s 大于或等于零,说明售票厅的人数还未满可进入。执行后若s 小于零,则说明售票厅的人数已满不能进入。这个实现中同时最多允许20 个进程进入售票厅购票,其余进程只能等待。 用PV 原语实现进程的同步 与进程互斥不同,进程同步时的信号量只与制约进程及被制约进程有关而不是与整组并发进程有关,所以称该信号量为私有信号量。利用PV 原语实现进程同步的 方法是:首先判断进程间的关系为同步的,且为各并发进程设置私有信号量,然后为私有信号量赋初值,最后利用PV 原语和私有信号量规定各进程的执行顺序。下 面我们将例1 增添一个条件,使其成为进程间是同步的。 例3 在例1 的基础之上再添加一个功能: (3)当一个进程拣了一个棋子(黑子或白子)以后,必让另一个进程拣一个棋子(黑子或白子)。 分析: 第一步:确定进程间的关系。由功能(1)(2)(3)可知,进程间的关系为同步关系。第二步:确定信号量及其值。进程A 和B 共享箱子这个公有 资源,但规定两个进程必须轮流去取不同色的棋子,因而相互间要互通消息。对于进程A 可设置一个私有信号量s1,该私有信号量用于判断进程A 是否能去拣黑 子,初值为1。对于进程B 同样设置一个私有信号量s2,该私有信号量用于判断进程B 是否能去拣白子,初值为0。当然你也可以设置s1 初值为0,s2 初值为 1。 实现: begin s1,s2:semaphore; s1:=1;s2:=0; cobegin process A begin L1:P(s1); 拣黑子; V(s2); goto L1; end; process B begin L2:P(s2); 拣白子; V(s1); goto L2; end; coend; end; 另外一个问题就是P 原语是不是一定在V 原语的前面?回答是否定的。下面看一个例子。 例4 设在公共汽车上,司机和售票员的活动分别是:司机:启动车辆,正常行车,到站停车。售票员:上乘客,关车门,售票,开车门,下乘客。用PV 操作对其控制。 分析: 第一步:确定进程间的关系。司机到站停车后,售票员方可工作。同样,售票员关车门后,司机才能工作。所以司机与售票员之间是一种同步关系。 第二步:确定信号量及其值。由于司机与售票员之间要互通消息,司机进程设置一个私有信号量run,用于判断司机能否进行工作,初值为0。售票员进程设置一个私有信号量stop,用于判断是否停车,售票员是否能够开车门,初值为0。 实现: begin stop,run:semaphore stop:=0;run:=0; cobegin driver:begin L1:P(run); 启动车辆; 正常行车; 到站停车; V(stop); goto L1; end; conductor:begin L2:上乘客; 关车门; V(run); 售票; P(stop); 开车门; 下乘客; goto L2; end; coend; end; 用PV 操作还可以实现进程同步与互斥的混合问题,典型的如:多个生产者和多个消费者共享容量为n 的缓存区。这个例子在很多书中都有介绍,在这里就不说了。 本文转自同步和通讯的目的是一样的,实现进程间数据共享,同步只是为了做到处理协同。共享内存在Win9X平台上是有的,在NT内核以后就没有这一说了,因为进程地址空间不再有共用部分Linux :通信就是说进程之间传递数据。常见的方法有 pipe(管道),FIFO(命名管道),socket(套接字),SysVIPC 的 shm(共享内存)、msg queue(消息队列),mmap(文件映射)。以前还有 STREAM,不过现在比较少见了(好像)。同步的意思是说,让不同进程能够在同时到达一个已知的特定状态之前等待另一方的执行。Linux 下常见的同步方法有SysVIPC 的 sem(信号量)、file locking / record locking(通过 fcntl 设定的文件锁、记录锁)、futex(基于共享内存的快速用户态互斥锁)。针对线程(pthread)的还有 pthread_mutex 和 pthread_cond(条件变量)。除了这些特定的同步对象之外,还有一些同步方法是与通信方法不可分离的,包括:对 pipe/FIFO/socket 和 msg queue 的阻塞等待、对子进程退出事件的等待(wait族)、对线程退出时间的等待(pthread_join)另外还有一个不能不提的,就是信号。欢迎分享,转载请注明来源:夏雨云
评论列表(0条)