cmd参数值 | 说明 |
SETVAL | 设置信号量集中信号量的计数值(也就是表示当前信号量集中有多少个信号),需要通过一个联合体中来设置,需要左后一个变长参数,就是当前联合体。 |
GETVAL | 获取信号量集中有多少个信号量。不需要最后一个变长参数,并且函数的返回值表示了当前可用的信号数量。 |
IPC_STAT | 把semid_ds结构体中的数据设置为信号集当前关联值。 |
IPC_SET | 在进程有足够的权限下,吧信号集当前的关联值设置为semid_ds结构体中的值。 |
IPC_RMID | 删除信号即,用法同消息队列和共享内存。 |
原子操作:
代码演示原子操作:
//com.h
#include
#include
#include
#include
#include
union semun
{
int val; //SETVAL的值
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};
//nums 表示当前信号集中有多少个信号量
//这里我们为二元信号量(互斥锁),所以num = 0
int CreateSem(int nums);
//semid 是CreateSem的返回值
//index 是设置当前信号集中第几个信号量,从0开始
//initval 是将当前信号量设置为initval值,表示临界资源的可用数目。
//这里我们为二元信号量(互斥锁),所以index = 0,initcval = 1
int InitSem(int semid,int index,int initval);
//获取当前信号量集的第index个信号量
//这里我们为二元信号量(互斥锁),所以index = 0
int GetSem(int index);
//对信号量集中的哪一个信号进行P操作
//这里我们为二元信号量(互斥锁),所以who = 0
int P(int semid,int who);
//对信号量集中的哪一个信号进行V操作
//这里我们为二元信号量(互斥锁),所以who = 0
int V(int semid,int who);
int DestorySem(int semid);
//com.c
#include "com.h"
int Command(int nums,int flags)
{
key_t key = ftok(".",0666);
if(key == -1)
{
perror("ftok");
exit(1);
}
int semid = semget(key,nums,flags);
if(semid < 0)
{
perror("semget");
exit(1);
}
return semid;
}
int CreateSem(int nums)
{
return Command(nums,IPC_CREAT | IPC_EXCL | 0666);
}
int InitSem(int semid,int index,int initval)
{
union semun _un;
_un.val = initval;
if(semctl(semid,index,SETVAL,_un) < 0)
{
perror("semctl initsem");
exit(1);
}
return 0;
}
int GetSem(int index)
{
return Command(index,IPC_CREAT);
}
int CommandPV(int semid,int who,int val)
{
struct sembuf buf;
buf.sem_num = who;
buf.sem_op = val;
buf.sem_flg = 0; //忽略这个操作
if(semop(semid,&buf,1) < 0)
{
perror("semop");
exit(1);
}
return 0;
}
int P(int semid,int who)
{
return CommandPV(semid,who,-1);
}
int V(int semid,int who)
{
return CommandPV(semid,who,1);
}
int DestorySem(int semid)
{
if(semctl(semid,0,IPC_RMID) < 0)
{
perror("semctl destrysem");
exit(1);
}
return 0;
}
//Print.c
#include "com.h"
#include
int main()
{
int semid = CreateSem(1);
InitSem(semid,0,1);
int pid = fork();
if(pid > 0) //parent
{
while(1)
{
P(semid,0);
printf("A");
usleep(654321);
printf("A ");
usleep(123456);
fflush(stdout);
V(semid,0);
}
}
else if(pid == 0) //child
{
while(1)
{
P(semid,0);
printf("B");
usleep(123456);
printf("B ");
fflush(stdout);
usleep(321456);
V(semid,0);
}
}
else
{
perror("fork");
exit(1);
}
DestorySem(semid);
return 0;
}
结果演示:没有出现单个A或者B交错出现的情况,符合预期
信号量也可以使用 ipcs -s 查看
可以使用 ipcrm -s [semid] 来删除