进程间通信---信号量互斥

公示栏案例引入

请添加图片描述

a同学写完“数学课”后出去接电话,b同学进来写了“英语课考试”,a同学后来又进来,写了“取消”,从而导致其他的同学看了产生歧义。

程序逻辑设计:

请添加图片描述

代码

student1.c



#include <fcntl.h>
#include<unistd.h>
void main(){
        int fd = 0;

        fd = open("./board.txt",O_RDWR|O_APPEND);
        /*写入 “数学课” */
        write(fd,"class math ",11);
        sleep(10);
        /* 写入“取消”  */
        close(fd);
}
~                                                                                                                                   
~                                                                                                                                   
~                                                                                                                                   
~                                                                                                                                   
~           

student2.c



#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>

void main(){
        int fd = 0;
        fd = open("./board.txt",O_RDWR|O_APPEND);
        /*  写入"英语课考试"   */
        write(fd,"enlish exam ",20);
        close(fd);
}
~                                                                                                                                   
~       

运行结果:
请添加图片描述

什么是信号量:

请添加图片描述
叙述一下:a进程 想操作文件前,先看 “标志” 是否为1,如果为1,则可以操作文件,【然后进行-1操作】。
如果 “标志” 为0,则等待…

这个标志 其实就是 信号量

信号量的实质:就是一个数字
图示中:获取 就是 减法 操作释放就是加法操作

信号量的概念:

请添加图片描述

信号量的分类:

请添加图片描述

比如数值的初始值为2则为 计数信号量

总体阐述:信号量操作 和文件操作 类比

请添加图片描述
打开信号量后可以获取到一个标示符这个标示符和 文件描述符fd相类似

键值是什么?

请添加图片描述
类比文件
通过 文件名 可以找到 文件
通过 键值 可以找到 信号量【即 键值和信号量进行关联】

如何指定键值

请添加图片描述

推荐使用:ftok()函数

ftok()函数的原理:
请添加图片描述

创建/打开信号量 函数

请添加图片描述

操作信号量semop()

请添加图片描述

注意:nsops:要操作几个信号量【之前也说过是信号量集合】
如果nsops>1,则参数sops应该为一个数组。

结构体struct sembuf*的说明:

struct sembuf {
u_short sem_num; /* semaphore # /
short sem_op; /
semaphore operation /
short sem_flg; /
operation flags */
};

请添加图片描述
注意:图中的1,2,3,4【0,1,2,3】不要过度关心。

sem_num:之前 创建/打开的是信号量集合,sem_num指的是这个集合中的第几个信号量
sem_op:假如sem_op为负数,获取不到的时候会等待

代码实例:利用信号量互斥 解决公示栏问题:

逻辑设计

请添加图片描述
student1.c


#include <fcntl.h>
#include<unistd.h>
void main(){
        int fd = 0;
        key_t key;
        int semid;
        struct sembuf sops;

        //创建键值
        key = ftok("/home",1);//第一个参数:文件名 ; 第二个参数:项目id

        //创建并打开信号量集合
        semid = semget(key,1,IPC_CREAT);//第二个参数:创建的这个信号量集合中包含一个信号量

        fd = open("./board.txt",O_RDWR|O_APPEND);

        //获取信号量
        sops.sem_num = 0;//集合中第几个信号量
        sops.sem_op = -1;
        semop(semid,&sops,1);//第三个参数为一共要操作多少个信号量

        /*写入 “数学课” */
        write(fd,"class math ",11);
        sleep(10);
        /* 写入“取消”  */
        write(fd,"is cancel ",11);

        //释放信号量
        sops.sem_num = 0;//集合中第几个信号量
        sops.sem_op = 1;
        semop(semid,&sops,1);//第三个参数为一共要操作多少个信号量

        close(fd);
}

student2.c
问题:b同学怎么找到a的这个信号量那?
请添加图片描述



#include<fcntl.h>
#include<sys/sem.h>
void main(){
        int fd = 0;
        key_t key;
        int semid;
        struct sembuf sops;

        //创建键值
        key = ftok("/home",1);

        //创建/打开信号量集合
        semid = semget(key,1,IPC_CREAT); //注意:此处即使加上了IPC_CREAT,但是系统发现key已经关联了一个信号量集合,所以调用semget()
函数不会再去创建一个信号量集合,而是打开已经有的信号量集合

        fd = open("./board.txt",O_RDWR|O_APPEND);

        //获取信号量
        sops.sem_num = 0;
        sops.sem_op = -1;
        semop(semid,&sops,1);

        /*  写入"英语课考试"   */
        write(fd,"enlish exam ",20);

        //释放信号量
        sops.sem_num = 0;
        sops.sem_op = 1;
        semop(semid,&sops,1);

        close(fd);
}
      

运行效果不符合预期:

经过在本机测试:本机中创建信号量集合以后 的信号量初始值是0,【视频中默认初始值好像是2,】究竟默认初始值为多少本人也不清楚,每台机器的现象可能不一致

问题原因:信号量的初始值不为1,在操作信号量前一定要通过semctl()检查信号量的初始值为多少

检查信号量的初始值:使用semctl()函数

修改以后的程序

student1.c

#include <sys/types.h>
#include <sys/ipc.h>
#include<stdio.h>
#include <sys/sem.h>
#include <fcntl.h>
#include<unistd.h>
void main(){
	int fd = 0;
	key_t key;
	int semid;
	struct sembuf sops;
	int ret;

	//创建键值
	key = ftok("/home",1);//第一个参数:文件名 ; 第二个参数:项目id
printf("key value is: %d\n",key);

	//创建并打开信号量集合
	semid = semget(key,1,IPC_CREAT);//第二个参数:创建的这个信号量集合中包含一个信号量
printf("semid is: %d\n",semid);


	//检查信号量的初始值
	ret = semctl(semid,0,SETVAL,1);
	ret = semctl(semid,0,GETVAL);//第二个参数0代表信号量在信号量集合中的序号
printf("semctl_getval  ret is %d\n",ret);
	
	fd = open("./board.txt",O_RDWR|O_APPEND);

	//获取信号量
	sops.sem_num = 0;//集合中第几个信号量
	sops.sem_op = -1;
	ret = semop(semid,&sops,1);//第三个参数为一共要操作多少个信号量
printf("semop ret is:  %d\n",ret);


	/*写入 “数学课” */
	write(fd,"class math ",11);
	sleep(10);
	/* 写入“取消”  */
	write(fd,"is cancel ",11);

	//释放信号量
	sops.sem_num = 0;//集合中第几个信号量
        sops.sem_op = 1;
        semop(semid,&sops,1);//第三个参数为一共要操作多少个信号量

	close(fd);
}



student2.c

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/sem.h>
void main(){
	int fd = 0;
	key_t key;
	int semid;
	struct sembuf sops;
	int ret;

	//创建键值
	key = ftok("/home",1);

	//创建/打开信号量集合
	semid = semget(key,1,IPC_CREAT); //注意:此处即使加上了IPC_CREAT,但是系统发现key已经关联了一个信号量集合,所以调用semget()函数不会再去创建一个信号量集合,而是打开已经有的信号量集合	

	fd = open("./board.txt",O_RDWR|O_APPEND);

	ret = semctl(semid,0,GETVAL);
	printf("semctl_GETVAL ret is: %d\n",ret );

	//获取信号量
	sops.sem_num = 0;
	sops.sem_op = -1;
	semop(semid,&sops,1);
	
	/*  写入"英语课考试"   */
	write(fd,"enlish exam ",20);

	//释放信号量
	sops.sem_num = 0;
        sops.sem_op = 1;
        semop(semid,&sops,1);

	close(fd);
}

运行结果:
b进程开启后等待,a,b全部结束后,查看board.txt的内容为:
请添加图片描述

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值