进程同步与互斥.ppt

上传人:牧羊曲112 文档编号:5320191 上传时间:2023-06-25 格式:PPT 页数:31 大小:417.97KB
返回 下载 相关 举报
进程同步与互斥.ppt_第1页
第1页 / 共31页
进程同步与互斥.ppt_第2页
第2页 / 共31页
进程同步与互斥.ppt_第3页
第3页 / 共31页
进程同步与互斥.ppt_第4页
第4页 / 共31页
进程同步与互斥.ppt_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《进程同步与互斥.ppt》由会员分享,可在线阅读,更多相关《进程同步与互斥.ppt(31页珍藏版)》请在三一办公上搜索。

1、2023/6/25,1,进程同步与互斥,2023/6/25,2,Linux提供下列3个有关信号量的系统调用函数:semget()semop()semctl()下面分别予以介绍。,2023/6/25,3,1.创建一个新的信号量集或获取一个已经存在的信号量集命令格式:int semget(key_t key,int nsems,int semflg);返回值:正确返回:信号量集的标识符错误返回:-1,2023/6/25,4,1.创建一个新的信号量集或获取一个已经存在的信号量集,参数说明:key信号量集的key值:使用IPC_PRIVATE,由系统产生key值并返回标识符,或者返回key值已存在的信

2、号量集的标识符。key值不为IPC_PRIVATE而是由用户指定一个非0整型数值,则对信号量集的打开或存取操作依赖于semflag参数的取值。nsems指定打开或者新创建的信号量集将包含的信号量的数目;如果该key值的信号量集已存在,而semflg只指定了IPC_CREAT标志,那么参数nsems必须与原来的值一致,否则也会返回错误信息。该参数最大值在linux/sem.h中被定义:#define SEMMSL 250/*=8 000*/semflg当key值不为IPC_PRIVATE:若只设置semflag的IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符若设

3、置semflag的IPC_CREAT|IPC_EXCL位,则创建一个新的信号量集,如果该key值的信号量集已经存在则返回错误信息只设置IPC_EXCL位而不设置IPC_CREAT位没有任何意义。,2023/6/25,5,1.创建一个新的信号量集或获取一个已经存在的信号量集,实验中,使用该调用创建一个只含一个信号量的信号量集,格式为:semid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);其中的IPC_PRIVATE可以使用具体的整型数值取代。,2023/6/25,6,2.对信号量的P、V操作,命令格式:int semop(int semid,struct semb

4、uf*sops,unsigned nsops);返回值:正确返回:0错误返回:-1参数说明:semid信号量集的标识符,由semget()得到。sops指向一个sembuf结构数组,该数组的每个元素对应一次信号量操作。,2023/6/25,7,2.对信号量的P、V操作,其sembuf数据结构如下:struct sembuf unsigned short sem_num;/*semaphore index in array*/shortsem_op;/*semaphore operation*/shortsem_flg;/*operation flags*/;其中的参数含义如下所示:,2023/

5、6/25,8,2.对信号量的P、V操作,信号量的sem_num值标明它是信号量集的第几个元素,第一个信号量为0,第二个为1,依次类推。semop确定对sem_num指定的信号量采取何种操作,它可以为负数、正数和零。如果sem_op为负数:则相当于P操作,从信号量的值中减去sem_op的绝对值:其差如果大于0,则表示该进程可以使用临界资源进入临界区;其差如果小于0,在没有指定IPC_NOWAIT的情况下,该进程睡眠,并插入sem_queues等待队列尾部,直到请求的条件得到满足;如果指定了IPC_NOWAIT,则出错返回。如果sem_op为正数:此时相当于V操作,把它的值加到信号量中,这也意味着

6、该进程释放资源。如果是互斥则出临界区,释放临界资源。如果sem_op为0:则该进程将睡眠直到信号量的值也为0。系统会按顺序检查信号量等待队列(sem_pending)中的每一个成员,查看在当前信号量的状态下,其请求的操作是否可以成功,如果可以,则将它从等待队列中唤醒,并插入到就绪队列中等待调度运行。sem_flg指明操作的执行模式,它有两个标志位:IPC_NOWAIT:指明以非阻塞方式操作信号量。SEM_UNDO:指明内核为信号量操作保留恢复值nsops是第二个参数所指向的sembuf结构数组中元素的个数,如果只有一个信号量nsops值为1。,2023/6/25,9,2.对信号量的P、V操作,

7、在实验中,使用该系统调用实现P、V操作,使用格式为:struct sembuf P,V;semop(semid,/对信号量semid执行V操作,2023/6/25,10,3信号量集的控制函数,命令格式:int semctl(int semid,int semnum,int cmd,union semun arg);返回值:操作成功返回:根据cmd的不同返回需要的值或0 错误返回:-1,2023/6/25,11,3信号量集的控制函数,参数说明:semid信号量集的标识符,由semget()得到;semnum指定semid信号量集的第几个信号量,在撤消信号量集时,此参数可以缺省;cmd用于指定操作

8、类别:SETVAL:置信号量semval域值为arg.val。IPC_RMID:删除指定信号量集。能够进行此项操作的进程限于超级用户、sem_perm.cuid或sem_perm.uid。,2023/6/25,12,3信号量集的控制函数,实验中使用该系统调用实现以下功能:为信号量赋初值,格式为:union semun arg;arg.val=初值;semctl(semid,0,SETVAL,arg);其中0表示第0个信号量,arg的值由arg.val决定,所以必须事先为arg.val赋值。撤消信号量集,格式为:semctl(semid,IPC_RMID,0);上述系统调用使用下列头函数:#in

9、clude#include,2023/6/25,13,信号量及其P、V操作的实现,信号量及其P、V操作的实现方式归纳如下:1 定义信号量标识符:int semid;如果有n个信号量,则需要分别定义n个不同的信号量标识符。2 定义信号量数据结构定义P、V操作所用的数据结构:struct sembuf P,V;定义给信号量赋初值的参数数据结构:union semun arg;3 申请只有一个信号量的信号量集semid=semget(IPC_PRIVITE,1,IPC_0666);其中,第一个参数:IPC_PRIVATE由系统产生key值,也可以由用户使用具体的整型数值作为key值指定;第二个参数表

10、示信号量集中只有一个信号量;操作权限取决于最后一个参数,0666表示任意用户可读可写,只设置semflag的IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符。4 分别对每个信号量semid赋初值arg.val=初值;semctl(semid,0,SETVAL,arg);,2023/6/25,14,信号量及其P、V操作的实现,5.定义信号量的P操作(供所有信号量的P操作使用)P.sem_num=0;P.sem_op=-1;/*-1表示P操作时对信号量减1*/P.sem_flg=SEM_UNDO;6.定义信号量的V操作(供所有信号量的V操作使用)V.sem_num=

11、0;V.sem_op=1;/*1表示V操作时对信号量加1*/V.sem_flg=SEM_UNDO;7.对信号量semid执行P操作:semop(semid,因为信号量不是普通变量,对它赋初值只能通过系统调用函数semctl(semid,0,SETVAL,arg)进行,其值的修改只能通过P、V操作,而不能使用普通的赋值语句。因此其初值和信号量的P、V操作需要事先定义好以后,然后才能在进程中执行P、V操作。,2023/6/25,15,应用举例,1.利用信号量实现进程互斥例4-9 设有父子2个进程共享一个临界资源,每个进程循环进入该临界区3次:父进程每次进入临界区后显示“prnt in”,出临界区则

12、显示“prnt out”;子进程每次进入临界区后显示“chld in”出临界区则显示“chld out”。观察运行结果,应该是一个进程出来后另一个才能进去。分析:对临界区设置互斥信号量mutex,其内部标识为mutexid,初值为1。程序中使用睡眠延时1秒来模拟进入临界区前和进入后所执行的程序。,2023/6/25,16,程序清单:文件名sem.c#include#include#include#include#includeint mutexid;/定义信号量标识int main()int chld,i,j;/*定义数据结构*/struct sembuf P,V;union semun ar

13、g;/*创建只含有一个互斥信号量元素的信号量集*/mutexid=semget(IPC_PRIVATE,1,0666|IPC_CREAT);/*为信号量赋初值*/arg.val=1;if(semctl(mutexid,0,SETVAL,arg)=-1)perror(semctl setval error);,2023/6/25,17,/*定义P、V操作*/P.sem_num=0;P.sem_op=-1;P.sem_flg=SEM_UNDO;V.sem_num=0;V.sem_op=1;V.sem_flg=SEM_UNDO;while(chld=fork()=-1);/创建子进程if(chld0

14、)/父进程返回i=1;while(i=3)/循环3次sleep(1);semop(mutexid,2023/6/25,18,else/子进程返回j=1;while(j=3)/循环3次sleep(1);semop(mutexid,/子进程终止,2023/6/25,19,编译连接及运行结果:,2023/6/25,20,利用信号量实现进程同步,例4-10 父进程创建一个子进程,父子进程共享一个存储区,子进程向共享存储区中以覆盖方式写信息,父进程从该共享存储区中读信息并显示信息。父子进程轮流读写,即子进程写一个信息到共享内存中,父进程从中读该信息输出;然后子进程再写第2个信息,父进程再读出第2个信息输

15、出,如图46所示。当信息为“end”时读写进程结束。,2023/6/25,21,利用信号量实现进程同步,同步分析:这是一个单缓冲区同步问题,在第3章中已经讨论过这类问题的同步算法,读写缓冲区的两个进程之间只需要同步不需要互斥,请参阅节中的单缓冲区同步问题。同步算法:子进程执行条件为单缓冲区有空,设信号量empty,初值为1;父进程执行条件为单缓冲区有数,设信号量full,初值为0;上述信号量可以由父进程定义、申请、初始化,然后由父子进程共享使用,子进程结束后由父进程撤消。共享内存设计:父子进程共享一个内存区,可以由父进程申请、附接,然后由父子进程共享使用,子进程结束后由父进程撤消。,2023/

16、6/25,22,程序清单,文件名为sem2.c:#include#include#include#include#include#include#include/*定义信号量内部标识*/int emptyid;int fullid;main()int chld,i,j;/*定义信号量数据结构*/struct sembuf P,V;union semun arg;/*定义共享内存*/int shmid;char*viraddr;char bufferBUFSIZ;,2023/6/25,23,/*创建信号量并初始化*/emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|0

17、666);fullid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);arg.val=1;if(semctl(emptyid,0,SETVAL,arg)=-1)perror(semctl setval error);arg.val=0;if(semctl(fullid,0,SETVAL,arg)=-1)perror(semctl setval error);/*定义P、V操作*/P.sem_num=0;P.sem_op=-1;P.sem_flg=SEM_UNDO;V.sem_num=0;V.sem_op=1;V.sem_flg=SEM_UNDO;/*创建并附接共享内

18、存*/shmid=shmget(IPC_PRIVATE,BUFSIZ,0666|IPC_CREAT);viraddr=(char*)shmat(shmid,0,0);,2023/6/25,24,while(chld=fork()=-1);/创建子进程if(chld0)/父进程返回读信息并输出 while(1)semop(fullid,2023/6/25,25,else/子进程返回写信息到共享内存while(1)semop(emptyid,2023/6/25,26,运行结果:,由结果可以看出,子进程写到单缓冲区中的信息,父进程都依次取出并输出了。,2023/6/25,27,利用信号量实现进程同步

19、,例4-11 设父进程创建一个子进程作为生产者,创建两个子进程作为消费者,这三个子进程使用一个共享内存,该共享内存定义为具有5个变量的数组,每个变量表示一个缓冲区,缓冲区号为04。生产者进程依次往缓冲区04中写10个数据110,两个读进程依次从缓冲区04中轮流取出这10个数据。使用信号量实现进程读写缓冲区的同步和互斥。,2023/6/25,28,利用信号量实现进程同步,分析:需要创建3个子进程:生产者、消费者A、消费者B;需要使用3个信号量:empty、full、mutex,分别表示缓冲区是否有空、是否有数和互斥信号量,其初值分别为:5,0,1;需要2个共享内存:array和get,分别表示多

20、缓冲区数组变量array 04、和消费者读缓冲区号的计数get,get计数由两个消费者进程共享,由于生产者只有一个没,所以写缓冲区号的计数set不需要使用共享内存。,2023/6/25,29,算法:,创建共享存储区array,get;附接共享存储区到进程空间;共享存储区赋初值;创建信号量empty并初始化;创建信号量full并初始化;创建信号量mutex并初始化;创建生产者子进程;如果生产者子进程返回:for(i=0;i10,i+)P(empty);P(mutex);写数据到共享存储区;缓冲区计数set+;V(mutex);V(full);exit(0);,如果父进程返回:创建消费者A子进程;

21、如果消费者A进程返回:for(i=0;i10,i+)P(full);P(mutex);从共享存储区中取数据;缓冲区计数(*get)+;V(mutex);V(empty);exit(0);如果父进程返回:创建消费者B子进程;如果消费者B进程返回:,2023/6/25,30,算法:,for(i=0;i10,i+)P(full);P(mutex);从共享存储区中取数据;缓冲区计数(*get)+;V(mutex);V(empty);exit(0);程序清单:semshm.doc,如果父进程返回:wait(0);wait(0);wait(0);断开2个共享存储区;撤消2个共享存储区;撤消3个信号量;exit(0);,2023/6/25,31,编译连接并执行后的输出结果如下:,由运行结果可以看出,生产者进程分别往缓冲区04中送了10次产品,消费者进程A和B轮流从缓冲区04中取走产品,并实现了3个进程之间的同步和互斥,即实现了生产者进程送了产品后消费者进程才取走产品,并且一次只有一个进程进入缓冲区。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号