进程同步与互斥-PPT精选

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include<sys/types.h>
#include<linux/sem.h>
int mutexid;
//定义信号量标识
int main()
{
int chld,i,j;
/*定义数据结构*/
struct sembuf P,V;
union semun arg;
/*创建只含有一个互斥信号量元素的信号量集*/
/* operation flags */
};
其中的参数含义如下所示:
2019/10/28
7
2.对信号量的P、V操作
⑴.信号量的sem_num值标明它是信号量集的第几个元素,第一个信号量为0,第二 个为1,依次类推。
⑵.semop确定对sem_num指定的信号量采取何种操作,它可以为负数、正数和零。
在实验中,使用该系统调用实现P、V操作,使用格式为:
struct sembuf P,V; semop(semid, &P, 1); semop(semid, &V, 1);
//对信号量semid执行P操作 //对信号量semid执行V操作
2019/10/2893.信号量集的控制函数
命令格式: int semctl(int semid, int semnum, int cmd, union
semflg——当key值不为IPC_PRIVATE:
①.若只设置semflag的IPC_CREAT位,则创建一个信号量集,如果该信号量集已 经存在,则返回其标识符
②.若设置semflag的IPC_CREAT|IPC_EXCL位,则创建一个新的信号量集,如果 该key值的信号量集已经存在则返回错误信息
③.只设置IPC_EXCL位而不设置IPC_CREAT位没有任何意义。
2019/10/28
4
1.创建一个新的信号量集或获取一个已经存在的信号量集
实验中,使用该调用创建一个只含一个信号 量的信号量集,格式为:
semid=semget(IPC_PRIVATE,1, IPC_CREAT|0666);
其中的IPC_PRIVATE可以使用具体的整型 数值取代。
进程同步与互斥
2019/10/28
1
Linux提供下列3个有关信号量的系统调用函数:
semget() semop() semctl()
下面分别予以介绍。
2019/10/28
2
1.创建一个新的信号量集或获取一个已经存在的信号量集
命令格式:
int semget(key_t key, int nsems, int semflg);
semctl(mutexid,IPC_RMID,0); //撤消信号量
exit(0);
}
2019/10/28
17
else {
} }
//子进程返回
j=1;
while(j<=3)
//循环3次
{
sleep(1);
semop(mutexid,&P,1); //进入临界区前执行P操作
printf("chld in\n");
semun arg);
返回值: 操作成功返回:根据cmd的不同返回需要的值或0
错误返回:-1
2019/10/28
10
3.信号量集的控制函数
参数说明: semid——信号量集的标识符,由semget()得到; semnum——指定semid信号量集的第几个信号量,在撤消
信号量集时,此参数可以缺省; cmd——用于指定操作类别:
则出错返回。
②.如果sem_op为正数:此时相当于V操作,把它的值加到信号量中,这也意味着该 进程释放资源。如果是互斥则出临界区,释放临界资源。
③.如果sem_op为0:则该进程将睡眠直到信号量的值也为0。
系统会按顺序检查信号量等待队列(sem_pending)中的每一个成员,查看在当前信号量
的状态下,其请求的操作是否可以成功,如果可以,则将它从等待队列中唤醒,并 插入到就绪队列中等待调度运行。
9. 撤消信号量:semctl(semid,IPC_RMID,0);
因为信号量不是普通变量,对它赋初值只能通过系统调用函数
semctl(semid,0,SETVAL,arg)进行,其值的修改只能通过P、V操作,而不能 使用普通的赋值语句。
因此其初值和信号量的P、V操作需要事先定义好以后,然后才能在进程中执行P、V 操作。
其中,第一个参数:IPC_PRIVATE由系统产生key值,也可以由用户使用 具体的整型数值作为key值指定;第二个参数表示信号量集中只有一个 信号量;操作权限取决于最后一个参数,0666表示任意用户可读可写, 只设置semflag的IPC_CREAT位,则创建一个信号量集,如果该信号量 集已经存在,则返回其标识符。
返回值: 正确返回:信号量集的标识符 错误返回:-1
2019/10/28
3
1.创建一个新的信号量集或获取一个已经存在的信号量集
参数说明:
key——信号量集的key值:
①.使用IPC_PRIVATE,由系统产生key值并返回标识符,或者返回key值已存在的 信号量集的标识符。
②. key值不为IPC_PRIVATE而是由用户指定一个非0整型数值,则对信号量集的打 开或存取操作依赖于semflag参数的取值。
arg.val赋值。 ⑵.撤消信号量集,格式为: semctl(semid,IPC_RMID,0); 上述系统调用使用下列头函数: #include<sys/types.h> #include<linux/sem.h>
2019/10/28
12
信号量及其P、V操作的实现
信号量及其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(chld>0)
//父进程返回
{
i=1;
while(i<=3)
1. 定义信号量标识符:int semid;
如果有n个信号量,则需要分别定义n个不同的信号量标识符。
2. 定义信号量数据结构
⑴.定义P、V操作所用的数据结构:struct sembuf P,V;
⑵.定义给信号量赋初值的参数数据结构:union semun arg;
3. 申请只有一个信号量的信号量集 semid=semget(IPC_PRIVITE,1,IPC_0666);
2019/10/28
14
应用举例
1.利用信号量实现进程互斥
[例4-9] 设有父子2个进程共享一个临界资源,每个进程循环进入该临界 区3次:父进程每次进入临界区后显示“prnt in”,出临界区则显示 “prnt out”;子进程每次进入临界区后显示“chld in”出临界区则显 示“chld out”。观察运行结果,应该是一个进程出来后另一个才能 进去。
⑶.sem_flg指明操作的执行模式,它有两个标志位: IPC_NOWAIT:指明以非阻塞 方式操作信号量。 SEM_UNDO: 指明内核为信号量操作保留恢复值
nsops——是第二个参数所指向的sembuf结构数组中元素的个数,如果只有一个信号 量nsops值为1。
2019/10/28
8
2.对信号量的P、V操作
P.sem_flg=SEM_UNDO;
6. 定义信号量的V操作(供所有信号量的V操作使用)
V.sem_num=0;
V.sem_op=1;
/*1表示V操作时对信号量加1*/
V.sem_flg=SEM_UNDO;
7. 对信号量semid执行P操作:semop(semid,&P,1);
8. 对信号量semid执行V操作:semop(semid,&V,1);
①.如果sem_op为负数:则相当于P操作,从信号量的值中减去sem_op的绝对值:

其差如果大于0,则表示该进程可以使用临界资源进入临界区;

其差如果小于0,在没有指定IPC_NOWAIT的情况下,该进程睡眠,并插入
sem_queues等待队列尾部,直到请求的条件得到满足;如果指定了IPC_NOWAIT,
SETVAL:置信号量semval域值为arg.val。 IPC_RMID:删除指定信号量集。能够进行此项操作的 进程限于超级用户、 sem_perm.cuid或sem_perm.uid。
2019/10/28
11
3.信号量集的控制函数
实验中使用该系统调用实现以下功能: ⑴.为信号量赋初值,格式为: union semun arg; arg.val=初值; semctl(semid,0,SETVAL,arg); 其 中 0 表 示 第 0 个 信号量 , arg的 值由 arg.val决 定 , 所 以必须 事 先 为
分析:
对临界区设置互斥信号量mutex,其内部标识为mutexid,初值为1。 程序中使用睡眠延时1秒来模拟进入临界区前和进入后所执行的程序。
2019/10/28
15
程序清单:文件名sem.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
2019/10/28
5
2.对信号量的P、V操作
命令格式: int semop(int semid, struct sembuf * sops, unsigned nsops); 返回值: 正确返回:0 错误返回:-1 参数说明: semid——信号量集的标识符,由semget()得到。 sops——指向一个sembuf结构数组,该数组的每个元素对应一次信
号量操作。
2019/10/28
6
2.对信号量的P、V操作
其sembuf数据结构如下:
struct sembuf
{
unsigned short sem_num; /* semaphore index in array */
short sem_op;
/* semaphore operation */
short sem_flg;
子进程
单缓冲区
图4-6 单缓冲区同步问题
父进程
2019/10/28
20
利用信号量实现进程同步
⑴.同步分析:
这是一个单缓冲区同步问题,在第3章中已经讨论过这类问题的同步算 法,读写缓冲区的两个进程之间只需要同步不需要互斥,请参阅 3.3.6节中的单缓冲区同步问题。
⑵.同步算法:
//循环3次
{
sleep(1);
semop(mutexid,&P,1); //进入临界区前执行P操作
printf("prnt in\n");
sleep(1);
printf("prnt out\n");
semop(mutexid,&V,1); //出临界区执行V操作
i++;
}
wait(0);
//等待子进程终止
4. 分别对每个信号量semid赋初值
arg.val=初值;
semctl(semid,0,SETVAL,arg);
2019/10/28
13
信号量及其P、V操作的实现
5. 定义信号量的P操作(供所有信号量的P操作使用)
P.sem_num=0;
P.sem_op=-1;
/*-1表示P操作时对信号量减1*/
sleep(1);
printf("chld out\n");
semop(mutexid,&V,1); //出临界区执行V操作
j++;
}
exit(0);
//子进程终止
2019/10/28
18
编译连接及运行结果:
2019/10/28
19
利用信号量实现进程同步
[例4-10] 父进程创建一个子进程,父子进程共享一个存储区,子进程向共享存储 区中以覆盖方式写信息,父进程从该共享存储区中读信息并显示信息。父子 进程轮流读写,即子进程写一个信息到共享内存中,父进程从中读该信息输 出;然后子进程再写第2个信息,父进程再读出第2个信息输出,如图4-6所 示。当信息为“end”时读写进程结束。
nsems——指定打开或者新创建的信号量集将包含的信号量的数目;如果该key值的 信号量集已存在,而semflg只指定了IPC_CREAT标志,那么参数nsems必须与 原来的值一致,否则也会返回错误信息。该参数最大值在linux/sem.h中被定义:
#define SEMMSL 250 /* <= 8 000 */
mutexid=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
/*为信号量赋初值*/
arg.val=1;
if(semctl(mutexid,0,SETVAL,arg)==-1)
perror("semctl setval error");
2019/10/28
16
/*定义P、V操作*/
相关文档
最新文档