信号量实现
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
// int semop(int semid, struct sembuf *sops, unsigned nsops);
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
void pGetKey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = -1;
set.sem_flg = SEM_UNDO;
semop(id,&set,1);
printf("get key\n");
}
void vPutBackKey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = 1;
set.sem_flg = SEM_UNDO;
semop(id,&set,1);
printf("put back the key\n");
}
int main(int argc,char const *argv[])
{
//1.获取或创建信号量
//int semget(key_t key, int nsems, int semflg);
//_nsems 表示初始化信号量的个数。比如我们要创建一个信号量,则该值为1.,创建2个就是2。
/*semflg :信号量的创建方式或权限。有IPC_CREAT,IPC_EXCL。
IPC_CREAT如果信号量不存在,则创建一个信号量,否则获取。
IPC_EXCL只有信号量不存在的时候,新的信号量才建立,否则就产生错误。*/
int semid;//创建或获取信号量返回的信号量ID值,成功返回信号量的标识码ID。失败返回-1;
key_t key;
key = ftok(".",2);//调用ftok函数,系统随机生成一个唯一的key,也可以手工输入一个key值,如0x1234
semid = semget(key,1,IPC_CREAT|0666);//1:信号量集合中有1个信号量;0666表示权限
//2.初始化信号量
//int semctl(int semid, int semnum, int cmd, ...);
/* semctl 功能:对信号量进行控制
参数:semid, 信号量标识符
sem_num, 信号量组中的编号,从0开始,如果只有一个信号量,则取0
cmd, SETVAL 把信号量初始化为指定的值,具体的值由第4个参数确定
注意:只能对信号量初始化一次,如果在各进程中,分别对该信号量进行初始化,则可能导致错误!
cmd命令,表示要进行的操作。
参数cmd中可以使用的命令如下:
IPC_STAT 读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
IPC_SET 设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID 将信号量集从内存中删除。
GETALL 用于读取信号量集中的所有信号量的值。
GETNCNT 返回正在等待资源的进程数目。
GETPID 返回最后一个执行semop操作的进程的PID。
GETVAL 返回信号量集中的一个单个的信号量的值。
GETZCNT 返回这在等待完全空闲的资源的进程数目。
SETALL 设置信号量集中的所有的信号量的值。
SETVAL 设置信号量集中的一个单独的信号量的值。
此函数有三个或四个参数,具体取决于cmd。当有四个时,第四个具有类型union semun。调用程序必须按man中方式定义此并集:
参数4, 类型为:
union semun {
int val; // SETVAL命令要设置的值
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
注意:union semun类型要求自己定义,有些Linux发行版在sys/sem.h中定义,有些发行版则没有定义。*/
union semun initsem;//定义一个第四个参数,联合体
initsem.val = 0;
semctl(semid,0,SETVAL,initsem);//初始化信号量,0:操作第0个信号量,SETVAL:表示需要设置的是信号量的值,其值设置为initsem
int pid = fork();
if(pid > 0){
pGetKey(semid);//去拿锁
printf("this is father\n");
vPutBackKey(semid);//锁放回去
semctl(semid,0,IPC_RMID);//销毁锁
}else if(pid == 0){
printf("this is child\n");
vPutBackKey(semid);
}else{
printf("fork error\n");
}
return 0;
}