第16课-信号量互斥编程

16.1 公示栏问题(问题引入)

1. 问题描述

这里面我们举一个小例子。在一个班级里就有一个公示栏,A同学想写“数学课考试”,B同学想写“英语课取消”。但是有一个时间,A同学只写下了“数学课”三个字,没来得及写后面的内容就出去了,但是这个时候B同学来写下了“英语课取消”。这样让同学们看来就成了“数学课英语课取消”,给班级的其他同学造成了歧义。

这也就是我们说的同时访问一个资源,造成了,数据的混乱。若是有多个进程同时访问一个资源,同样会造成这个问题。

2. 问题程序化

A同学用进程A代替,B同学用进程B代替,公示栏用文件来代替。我们在先关课程的文件夹里面建立student1.c和student2.c。

注:这里加入一个操作---ctil+shift+t可以完成复制一个一样的命令栏窗口。

stduent1程序:

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

void main()

{

int fd = 0;

//0.打开文件

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

//1.向公告板文件里面写入“数学课”

write(fd,"math class",11);

//2.暂停休息

sleep(5);

//3.向公告板文件里写入“取消”

write(fd,"is cancel",11);

close(fd);

}

stduent2程序:

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

void main()

{

int fd = 0;

//0.打开文件

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

//1.向公告板文件里面写入“英语课考试”

write(fd,"English exam",20);

//2.关闭文件

close(fd);

}

运行结果:我们开起两个中断在一个终端中运行:./stduent1,5s内在另一个终端中运行./stduent2。我们查看提前创建好的board.txt文件显示为:math class English exam


;is cancel

3. 信号量概念

为了能够是一个程序不会出现访问混乱的情况,我们可以说白一点,像厕所一样,有人进入就有标识牌显示有人,即使时间很长。从而达到了互斥的访问。这一个概念就是信号量。

l  概念:信号量(又名:信号灯)与其他进程间通讯方式不大相同,主要用途是保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于控制外,还可以用于进程同步。

l  分类:

二值信号灯:信号灯的值只能取0或1;

计数信号灯:信号灯的值可以取任意非负值。

l  信号量使用流程:

1)         打开信号量,获得标示符

2)         利用标示符,进行一系列操作

16.2 函数学习

1. 创建/打开信号量

(1)函数名

semget

(2)函数原型

int semget(key_t key, int nsems, int semflg);

(3)函数功能

获取信号量集合(一个信号或者多个信号)的标示符(get a semaphore set identifier),当key所指的信号量不存在,并且semflg里面包含了IPC_CREAT,就会创建这个信号量集合。

(4)所属头文件

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/sem.h>

(5)返回值

成功:返回信号量集合的标示符;

失败:-1.

(6)参数说明

l  什么是“键值”:(文件创建有文件名,使用文件的时候有文件的fd(id号);ipc对象创建的时候有键值(一个数字),使用的时候有标示符)对于一个文件,我们只要找到文件名,我们就能找到文件id(fd),打开文件。对于一个信号量(ipc对象)无论使用还是没有使用都是具有键值的,我们要知道他的“键值”我们就能打开它的标示符。标示符是打开这个ipc对象才会有的,键值是无论打开与没打开都有的。无论是A进程还是B进程,我们要找到它的信号量,我们都要知道它的“键值”。在我们创建信号量的时候(创建之后就会产生),我们就为它指定了键值。键值如何选取呢(在ipc对象创建的时候)?这里我们给出两个方法:

(1)任意指定一个数

缺点:这个数已经被别的IPC对象(消息队列,共享内存)所使用了,在于新创建的信

量关联时就会失败。

(2)构造一个尽量不会被别的IPC对象用到的数的方法:使用key_t ftok(char *fname,int id)

这个函数有两个参数,第一个是文件名,第二个是项目id。根据这个文件名,我们可以得到一个数字,这个数字,是文件在内核里面保存文件信息的一个文字。将这个数字再和项目id组合起来,就形成我们所要的键值了。这个键值的数字的产生:内核中保存该文件名的结构中的一个数字 + 项目id,这样形成的一个数字。也就是我们知道文件名和项目id可以得到ipc对象的键值,知道ipc对象的键值可以得到ipc对象的标示符。

每个进程的标示符有唯一的键值与之对应。

key:打开的信号量对应的键值。

semflg:标志,可以取IPC_CREAT,当key所指的信号量不存在,并且semflg里面包含了IPC_CREAT,就会创建这个信号量集合。

nsems:创建的这个信号量集合里面包含的信号量数目,是个数字。

2. 操作信号量

(1)函数名

semop

(2)函数原型

int semop(int semid, struct sembuf *sops, unsigned nsopos);

(3)函数功能

操作信号量集合里面的信号量。

(4)所属头文件

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/sem.h>

(5)返回值

成功:0;

失败:-1.

(6)参数说明

semid:要操作的信号量集合(可以一个可以多个)的标示符。

sembuf:它包含下面的集合,

unsigned short sem_num;  /*semaphore number*/ 操作的信号量集合的编号

short        sem_op;   /*semphore operation*/ 正数表示释放(+1),负数表示获取(-1),不成功导致程序等待

short        sem_flg;   /*operation flags*/

nsops:一共操作了多少的信号量

sops:对信号量执行了什么样的操作,一个指针对应一个操作,若是有三个操作,就是组数为3的数组。

16.3 综合实例编程

A在使用黑板前获取信号量,然后开始使用黑板。使用黑板的时候,信号量的值应该是0。使用完了黑板释放信号量,信号量变成1。由于是A同学率先使用这个信号量的,所以要由A同学来创建这个信号量。

B同学在使用的时候在先获取信号量,能够获取的到,就直接使用。若在获取的过程中,发现这个信号量被A获取了,就等待直到A同学使用完毕。B同学使用完信号量,释放信号量。

stduent1.c

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

#include<sys/ipc.h>

#include<sys/sem.h>

void main()

{

int fd = 0;

int semid;

key_t key;

struct sembuf sops;

//创建信号量的键值

key = ftok("/home",1); //使用文件名,和数字的方式,可以任意组合。

//创建并打开信号量

semid = semget(key,1,IPC_CREAT);//在系统中没有这个信号量,用参数IPC_CREAT;//就用一个信号量,使用数字1

//0.打开文件

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

//1.1 获取信号量

sops.sem_num = 0;  //我们的信号量集合里面只有一个信号,我们操作的信号的序//号一定是0

sops.sem_op = -1;   //-1表示获取这个信号量

semop(semid,&sops,1); //操作一个信号量,第三个参数用1;第二个参数表示执行什么样的操作

//1.向公告板文件里面写入“数学课”

write(fd,"math class",11);

//2.暂停休息

sleep(10);

//3.向公告板文件里写入“取消”

write(fd,"is cancel",11);

//释放信号量

sops.sem_num = 0; //第一个信号量

sops.sem_op = 1;  //释放信号量,+1的操作

semop(semid,&sops,1);

close(fd);

}

Stduent2.c

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

#include<sys/ipc.h>

#include<sys/sem.h>

void main()

{

int fd = 0;

int semid;

key_t key;

struct sembuf sops;

//创建信号量的键值

key = ftok("/home",1); //保证两个学生操同一个信号量,键值的组成是一样的。

//打开信号量集合

semid = semget(key,1,IPC_CREAT);

//0.打开文件

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

//获取信号量

sops.sem_num = 0;

sops.sem_op = -1;

semop(semid,&sops,1);

//1.向公告板文件里面写入“英语课考试”

write(fd,"English exam",12);

//释放信号量

sops.sem_num = 0;

sops.sem_op = 1;

semop(semid,&sops,1);

//2.关闭文件

close(fd);

}

运行结果:当我们在两个终端中分别运行./student1和./student2时,我们按道理应该看到的情况是,第一个程序在等待,第二个程序也在等待,直到第一个程序完成。并且写入的数据不混乱。但是,我们这两种期望都没看到。运行B程序,瞬间就结束了;写入的数据也不对。这里我们忽略了一个东西,我们前面一直在做一个假设,就是信号量的初始值是1。

实际的信号量的值不一定是1,可能是4、5、6等其他值。

这里我们引入另一个函数:semctl

函数原型

int semctl(int semid , int sennum, int cmd,.../*union semum arg*/);  //有10种,我们用到GETVAL这个命令

下面在student.c加入这两行命令:    int ret;

ret = semctl(semid,1,GETVAL);

发现它的初始值是:-1;

下面是更改后的程序

student1.c

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

#include<sys/ipc.h>

#include<sys/sem.h>

void main()

{

int fd = 0;

int semid;

key_t key;

int ret;

struct sembuf sops;

//创建信号量的键值

key = ftok("/home",1);

//创建并打开信号量集合

semid = semget(key,1,IPC_CREAT);

ret = semctl(semid,0,SETVAL,1);  //给信号量赋初值:1

printf("init value of sem is %d\n",ret);

//0.打开文件

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

//1.1 获取信号量

sops.sem_num = 0;

sops.sem_op = -1;

semop(semid,&sops,1);

//1.向公告板文件里面写入“数学课”

write(fd,"math class",11);

//2.暂停休息

sleep(10);

//3.向公告板文件里写入“取消”

write(fd,"is cancel",11);

//释放信号量

sops.sem_num = 0;

sops.sem_op = 1;

semop(semid,&sops,1);

close(fd);

}

student2:

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

#include<stdio.h>

#include<sys/ipc.h>

#include<sys/sem.h>

void main()

{

int fd = 0;

int semid;

key_t key;

struct sembuf sops;

int ret;

//创建信号量的键值

key = ftok("/home",1);

//打开信号量集合

semid = semget(key,1,IPC_CREAT);

//0.打开文件

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

ret = semctl(semid,0,GETVAL); //看看信号量的值是多少

printf("ret is %d\n",ret);

//获取信号量

sops.sem_num = 0;

sops.sem_op = -1;

semop(semid,&sops,1);

//1.向公告板文件里面写入“英语课考试”

write(fd,"English exam",12);

//释放信号量

sops.sem_num = 0;

sops.sem_op = 1;

semop(semid,&sops,1);

//2.关闭文件

close(fd);

}

运行结果:在两个终端中分别运行./student1和./student2。我们能看到等待的出现。board.txt中的内容是:math class is cancel English exam

这就是我们要的结果。

转载于:https://www.cnblogs.com/free-1122/p/11351438.html

第三季-第16课-信号量互斥编程相关推荐

  1. AI一分钟 | 教育部公布高中新课标,编程、算法思维成必修内容;李彦宏否认百度会“All in AI”

    一分钟AI 李彦宏表示自己做事一向留有余地,否认百度会"All in AI". 教育部发布最新高中课程改革方案,对学生在编程.算法.人工智能和开源硬件方面的要求大幅度提升. 罗永浩 ...

  2. 信号量 互斥量 条件变量

    原文:https://blog.csdn.net/qq_32646795/article/details/78221005 本文打算写一些和锁有关的东西,谈一谈我对锁的原理和实现的理解,主要包含以下方 ...

  3. Emojify - v2 吴恩达老师深度学习第五课第二周编程作业2

    吴恩达老师深度学习第五课第二周编程作业2,包含答案! Emojify! Welcome to the second assignment of Week 2. You are going to use ...

  4. python编程16章_Python核心编程——Chapter16

    好吧,在拜读完<Python网络编程基础>之后,回头再搞一搞16章的网络编程吧. Let's go! 16.4.修改书上示例的TCP和UDP客户端,使得服务器的名字不要在代码里写死,要允许 ...

  5. Windows事件等待学习笔记(四)—— 事件信号量互斥体

    Windows事件等待学习笔记(四)-- 事件&信号量&互斥体 要点回顾 事件 实验:验证SignalState 第一步:编译并运行以下代码 第二步:观察结果 第三步:修改代码并执行 ...

  6. linux 信号量锁 内核,Linux内核信号量互斥锁应用

    主要介绍了Linux 内核关于信号量,互斥锁等的应用 内核同步机制-信号量/互斥锁/读-写信号量 sema ,mutex ,rwsem 信号量 通用信号量 用户类进程之间使用信号量(semaphore ...

  7. 微课|《Python编程基础与案例集锦(中学版)》第5章例题讲解(1)

    适用教材:<Python编程基础与案例集锦(中学版)>,董付国,应根球著,电子工业出版社 京东图书地址:https://item.jd.com/12571990.html 当当图书地址:h ...

  8. 微课|《Python编程基础与案例集锦(中学版)》第4章例题讲解(3)

    适用教材:<Python编程基础与案例集锦(中学版)>,董付国,应根球著,电子工业出版社 例4-10  把十进制数转换为其他进制形式. 例4-11  验证6174猜想. 例4-12.例4- ...

  9. 微课|《Python编程基础与案例集锦(中学版)》第4章例题讲解(2)

    适用教材:<Python编程基础与案例集锦(中学版)>,董付国,应根球著,电子工业出版社 例4-4 例4-5 例4-6 微课|中学生可以这样学Python(例4.3):百钱买百鸡 例4-7 ...

  10. 微课|《Python编程基础与案例集锦(中学版)》第4章例题讲解(1)

    适用教材:<Python编程基础与案例集锦(中学版)>,董付国,应根球著,电子工业出版社 例4-1 例4-2 例4-3 京东图书地址:https://item.jd.com/1257199 ...

最新文章

  1. Vert.x!这是目前最快的 Java 框架
  2. 雅虎宣布关闭旗下7个数字杂志
  3. Buck降压电路仿真与解析
  4. 语音识别维特比解码_HMM连续语音识别中Viterbi算法的优化及应用
  5. 设置图片元素上下垂直居中的7种css样式_赵一鸣博客
  6. 计算机应用基础第二章,计算机应用基础第二章上机操作题
  7. 首个诞生于长期支持计划的版本Node.js 4.2 “Argon”正式发布
  8. Selenium自动化测试-设置元素等待
  9. 提高计算机技能操作水平,计算机操作技能比赛方案
  10. LRU原理和Redis实现
  11. Java从入门到精通 第11章 枚举
  12. 对一个“老”架构的重新思考
  13. 常用测试工具-----XCAP
  14. 中国新材料产业应用前景与十四五运营方向分析报告2021年版
  15. xp系统做无盘服务器,锐起无盘网吧系统无盘XP系统特点
  16. 电子锁c语言源程序数码管显示,基于C语言51单片机电子密码锁的设计与仿真
  17. 酒店系统主服务器是什么意思,酒店主服务器硬件配置
  18. java中继承的介绍
  19. 在html中div水平垂直css,html中div使用CSS实现水平/垂直居中的多种方式
  20. ead开局 华三inode_03 EAD用户接入-受控软件管理-新华三集团-H3C

热门文章

  1. Java设计模式------工厂模式-------工厂方法模式
  2. Apache Flink ML 2.0.0 发布公告
  3. 安卓滚动字幕以及TextSwitcher、ImageSwitcher使用
  4. Android的JNI【实战教程】2⃣️--AS下NDK环境配置及第一个工程
  5. Tomcat无法启动:Server Tomcat v8.5 Server at localhost failed to start
  6. Python的学习必备基础知识总结
  7. mysql sql执行慢_Mysql执行查询语句慢的解决方式
  8. linux下mail函数,Linux主机禁用Mail函数的解决办法
  9. 仓库出租平台有哪些_日用品仓库出租哪家划算周到
  10. oracle12c dba或者sys身份的账户和密码,怎么一次性安装好oracle 12c依赖包