原文链接https://blog.csdn.net/qq_27312943/article/details/79067893
1. 公示栏问题
两个同学交叉的使用公示栏发布公告,导致两者的信息发布的都不对
astudent: class match cancel
bstudent: english exam
公示栏问题 程序化
astudent:
//a student 写入数据后进行休息,然后再进行写入数据 #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> void main() { int fd; fd=open("./board.txt",O_RDWR|O_APPEND); if(fd<0) { printf("open file error\n"); } write(fd,"class math",10); printf("class math\n"); sleep(10); write(fd,"is cancel",9); close(fd); //关闭文件 }
bstudent:
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> void main() { int fd=open("./board.txt",O_RDWR|O_APPEND); if(fd<0) { printf("file open error\n"); exit(0); } write(fd,"english exam",12); close(fd); }
先执行astudent程序,在执行astudent时执行bstudent,最后打开board.txt查看内容
信号量(灯)
信号量(又名:信号灯)与其他进 程间通信方式不大相同,主要用 途是保护临界资源(进程互斥)。 进程可以根据它判定是否能够访问某些共享资源。除了用于访问 控制外,还可用于进程同步
信号量分类
- 二值信号灯:信号灯的值只能取0或1
- 计数信号灯:信号灯的值可以取任意非负值
利用信号量实现互斥访问
为使多个进程能互斥地访问某临界资源,只须为该资源设置一互斥信号量 mutex,并设其初始值为 1,然后将各进程访问该资源的临界区 CS 置于 wait(mutex)和 signal(mutex)操作之间即可。
这样,每个欲访问该临界资源的进程在进入临界区之前,都要先对 mutex 执行wait 操作,若该资源此刻未被访问,本次 wait 操作必然成功,进程便可进入自己的临界区,这时若再有其他进程也欲进入自己的临界区,此时由于对 mutex 执行 wait 操作定会失败,因而该进程阻塞,从而保证了该临界资源能被互斥地访问。当访问临界资源的进程退出临界区后,又应对 mutex 执行 signal 操作,以便释放该临界资源
信号量和文件对比
在linux系统中文件都有一个文件名(包含路径的文件名),通过open函数可以打开文件,同时open函数的返回值为一个整数,即文件描述符fd,利用文件描述符可以进行更多的操作,如write。
对信号量也有类似的操作,可以打开信号量,得到一个标示符,利用标示符可以对信号量进行更多的操作。
键值
信号量通过键值这样一个数字可以找到,
也就是说系统中的每一个IPC对象(如信号量,共享内存)都有一个键值与之对应,
键值是打开之前就有的,标示符是打开IPC对象之后才有的。
键值用来标明系统中的信号量,通过键值可以找到信号量。
键值的指定
键值是在信号量创建时指定的,指定键值的方式有两种。
- (1)任意指定一个数
缺点:这个数已经被别的IPC对象(消息队列,共享内存)所使用了,在与新创建的信号量关联时就会失败。
- (2)构造一个尽量不会被别的IPC对象用到的数
方法:使用key_t ftok( char * fname, int id )
键值指定-ftok:
函数原型
key_t ftok(const char *pathname,int proj_id);
函数功能
过将文件路径名和子序号,获得System V IPC 键值(即创建消息队列、共享内存所用的键值)
所属头文件
<sys/types.h><sys/ipc.h>
返回值
成功,则返回System V IPC键值。 失败,则返回-1。
参数说明
pathname:指定的带路径的文件名。 proj_id:子序号id,或称工程id。
函数学习
创建/获取信号量-semget
函数原型
int semget(key_t key, int nsems, int semflg);
函数功能
获取信号量集合的标识符,当key所指定的信号量不存在时并semflag为IPC_CREAT时创建信号量集合。
所属头文件
<sys/types.h> <sys/ipc.h> <sys/sem.h>
返回值
成功:返回信号量集合的标识符 失败:-1
参数说明
key: 要打开的信号量对应的键值。 semflag:标志,可以取IPC_CREAT,IPC_CREAT标明,如果key标识的信号量不存在时,创建信号量。 nsems: 创建的信号量集合里面包含的信号量数目。
操作信号量-semop/semctl
semop
函数原型
int semop(int semid, struct sembuf *sops, unsigned nsops);
函数功能
操作信号量集合里的信号量
所属头文件
<sys/types.h><sys/ipc.h>sys/sem.h>
返回值
成功:0 失败:-1
参数说明
semid:要操作的信号量集合的标识符 nsops:要操作多少个信号量 sops:对信号执行什么样的操作
semctl
函数原型
int semctl(int semid,int semnum,int cmd,union semun arg);
函数功能
信号灯的控制
所属头文件
<sys/types.h><sys/ipc.h>sys/sem.h>
返回值
失败时返回-1,成功返回与cmd相关的正数,例如: GETPID:返回sempid SETVAL:返回semval
参数说明
semid:信号灯集的ID. semnum:操作的信号灯编号。 cmd:是控制命令,常用的命令有 IPC_RMID:将信号灯集从内存中删除。 GETPID: 获得sempid GETVAL: 获得semval SETVAL: 设置semval
公告栏问题使用信号量解决
astuent
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.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); /* 设置信号量初始值为1 */ //信号量的初始值可以为任意值 semctl(semid,0,SETVAL,1); // //打开文件 fd=open("board.txt",O_RDWR|O_APPEND|O_CREAT,666); if(fd<0) { printf("error\n"); exit(0); } //获取信号量 //semop第一个参数是信号量集合,即semid //只操作一个信号量,所以第三个参数为1 sops.sem_num=0; sops.sem_op=-1; //获取信号量 semop(semid,&sops,1); //向公告栏中写入数据 write(fd,"class math",10); //暂停 sleep(10); write(fd,"is cancel",10); //释放信号量 sops.sem_num = 0; sops.sem_op = 1; semop(semid,&sops,1); close(fd); }
bstudent
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/sem.h> void main() { int fd = 0; key_t key; int semid; struct sembuf sops; int ret; /* 创建键值 */ //确保A,B打开的是同一个信号量,也就是说B必须指定相同的文件名和项目ID key = ftok("/home",1); /* 打开信号量集合 */ //A已经创建了一个信号量,此时不会创建新的信号量,会打开已有的信号量 semid = semget(key,1,IPC_CREAT); //打印信号量此时的值 ret = semctl(semid,0,GETVAL); printf("%d\n",ret); /* 打开公告板文件*/ fd = open("./board.txt",O_RDWR|O_APPEND); /* 获取信号量 */ sops.sem_num = 0; sops.sem_op = -1; //如果获取失败,进程会阻塞 semop(semid,&sops,1); /* 写入英语课“考试” */ write(fd," english exam",13); /* 释放信号量 */ sops.sem_num = 0; sops.sem_op = 1; semop(semid,&sops,1); close(fd); }