在程序中利用信号量互斥来解决公示板问题
背景知识
1、信号灯的概念
信号灯,又被称为信号量(semaphore),是IPC(进程间通信)的方式之一。它可以用来保证两个或多个关键代码段不被多个进程并发调用。每个信号灯都有个semval,用于记录信号灯的值。在进入一个关键代码段之前,进程必须获取一个信号量,使semval减1;一旦该关键代码段完成了,那么该进程必须释放信号量,使semval加1.其它想进入该关键代码段的进程,如果semval是0,就必须等待直到第一个进程释放信号量。
2、信号灯的用法
使用共享内存进行进程间通讯一般会经历下面几步:
1)建立信号灯集:进程通过调用函数semget来创建或者获得一个信号灯集;
2)初始化semval:通过semctl使用SETVAL命令来初始化信号灯的值(semval);
3)获取与释放semval:通过函数semop来获取或者释放信号灯,其中获取对应于semval值减1,释放对应于semval值加1.
4)删除信号灯集:当进程结束使用信号灯时,使用semctl通过IPC_RMID命令来删除它。
3、函数参考表
semget:
函数功能:创建与打开信号灯集
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
函数原型:int semget(key_t key,int nsems,int semflg);
参数说明:key:表示信号灯集的键值。当key的取值为IPC_PRIVATE,则函数semget()将创建一个新的信号灯集。
nsems:表示创建的信号灯集中的信号灯个数。
semflg:表示的操作类型,也可用于设置信号灯的访问权限,两者通过‘|‘连接表示。
返回值:成功,则返回信号灯的IPC标识符。失败,则返回-1,errno存储错误原因。
EACCESS:没有权限
EEXIST:信号灯集已经存在,无法创建。
EIDRM:信号灯集已经删除。
ENOENT:信号灯集不存在,同时没有使用IPC_CREAT.
ENOMEM:没有足够的内存创建新的信号灯集。
ENOSPC:超出限制。
ftok:
函数功能:通过将文件路径名和子序号,获得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,errno储存错误原因。
semop
函数功能:信号灯的操作函数
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
函数原型:int semop(int semid,struct sembuf *sops,unsigned nsops);
参数说明:semid:待操作的信号灯集ID。
sops:指向待操作的信号灯结构体(数组)。sembuf结构体包含了对于某个信号灯操作方法的信息,其成员如下:
unsigned short sem_num;//信号灯编号,从0开始
short sem_op;//为正时,代表释放的信号灯值,为负时代表获取是信号灯值
short sem_flg;//操作的标识
nsops:表示要操作的信号灯数。
返回值:成功时,这个函数返回共享内存的起始地址,失败时返回-1.
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
st1.c
st2.c
执行st1,进入睡眠
st2去获取信号量失败,则进行阻塞
当st1程序操作完成并释放了信号量之后,则st2重新获取信号量成功后,才得到运行。
查看board.txt文件