一 公示栏问题
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查看内容
二 信号量
1 信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是 保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。
2 信号量的分类
二值信号灯:信号灯的值只能取0或1
计数信号灯:信号灯的值可以取任意非负值。
函数功能:通过将文件路径名和子序号,获得System V IPC 键值(即创建消息队列、共享内存所用的键值)
头文件:
#include<sys/types.h>
#include<sys/ipc.h>
函数原型:key_t ftok(const char *pathname,int proj_id);
参数说明:pathname:指定的带路径的文件名。
proj_id:子序号id,或称工程id。
如指定文件的索引节点号为65538,,换算成16进制为0x010002,而指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
返回值:成功,则返回System V IPC键值。
失败,则返回-1。
函数原型:int semget(key_t key, int nsems, int semflg);
函数功能:获取信号量集合的标识符,当key所指定的信号量不存在时并semflag为IPC_CREAT时创建信号量集合。
头文件:<sys/types.h>
返回值:成功:返回信号量集合的标识符
参数说明:key:要打开的信号量对应的键值。
semflag:标志,可以取IPC_CREAT, IPC_CREAT标明,如果key标识的信号量不存在时,创建信号量。
nsems:创建的信号量集合里面包含的信号量数目。
操作信号量
函数名:semop
函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
函数功能:操作信号量集合里的信号量
头文件:<sys/types.h>
<sys/ipc.h>
<sys/sem.h>
返回值:成功:0 失败:-1
参数说明:semid:要操作的信号量集合的标识符
nsops:要操作多少个信号量
sops:对信号执行什么样的操作
the elements of this structure are of type struct sembuf,containing the following number:
unsigned short sem_num;/*semaphore number*/ //信号灯编号
short sem_op;/*semaphore operation*/ //为正时,代表释放的信号灯值,为负时,代表获取信号灯值
short sem_flg;/*operation flags*/ //操作的标识
semctl
函数名:semctl()
函数功能:信号灯的控制
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
函数原型:int semctl(int semid,int semnum,int cmd,union semun arg);
参数说明:
semid:信号灯集的ID.
semnum:操作的信号灯编号。
cmd:是控制命令,常用的命令有
IPC_RMID:将信号灯集从内存中删除。
GETPID:获得sempid
GETVAL:获得semval
SETVAL:设置semval
arg:是一个共同体类型的副本。其中各个量的使用情况和参数cmd的设置有关。
返回值:失败时返回-1,成功返回与cmd相关的正数,例如:
GETPID:返回sempid
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);
}
运行结果
参考:
1 https://www.cnblogs.com/gary-guo/p/5558861.html 信号量互斥编程
2 国嵌《信号量互斥编程》
3 http://blog.csdn.net/zhuwenfeng215/article/details/45267585 信号量互斥编程