二值信号灯:值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。
计数信号灯:值在0到n之间。用来统计资源,其值代表可用资源数
等待操作是等待信号灯的值变为大于0,然后将其减1;而释放操作则相反,用来唤醒等待资源的进程或者线程
System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯
System V 信号灯由内核维护
主要函数semget,semop,semctl
#include
#include
#include
#include
#include
#include
#include
#include
#define WRITE 0 # 生产者编号
#define READ 1 # 消费者编号
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) */
};
int main(int argc, char *argv[])
{
//1、创建共享内存
key_t key = ftok(".", 'a');
if (key < 0)
{
perror("ftok");
return -1;
}
// int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT|0777);
int shmid = shmget(key, 1024, IPC_CREAT|0777);
if (shmid < 0)
{
perror("shmget");
return -1;
}
//2. 把共享内存映射到用户空间
char *addr = shmat(shmid, NULL, 0);
if ((void *)-1 == addr)
{
perror("shmat");
return -1;
}
//初始化信号灯集:可生产不可消费 编号:0:生产者 1:消费者
int semid = semget(IPC_PRIVATE, 2, IPC_CREAT|0777);
if (semget < 0)
{
perror("semget");
return -1;
}
union semun sem0 = {1};
semctl(semid, WRITE, SETVAL, sem0); //生产者初始值:1
union semun sem1 = {0};
semctl(semid, READ, SETVAL, sem1); //消费者初始值:0
pid_t pid;
if (0 > (pid = fork()))
{
perror("fork");
return -1;
}
else if (0 == pid) //生产者
{
while (1)
{
//申请生产者的资源
struct sembuf sem0 = {WRITE, -1, 0}; //生产者:P操作
semop(semid, &sem0, 1);
printf("Input: ");
fgets(addr, 1024, stdin);
//释放消费者资源
struct sembuf sem1 = {READ, 1, 0}; //消费者:V操作
semop(semid, &sem1, 1);
if (strncmp(addr, "quit", 4) == 0)
break;
}
exit(0);
}
//消费者
while (1)
{
//申请消费者资源
struct sembuf sem1 = {READ, -1, 0}; //消费者:P操作
semop(semid, &sem1, 1);
printf("Recv: %s\n", addr);
//释放生产者资源
struct sembuf sem0 = {WRITE, 1, 0}; //生产者:V操作
semop(semid, &sem0, 1);
if (strncmp(addr, "quit", 4) == 0)
break;
}
//3. 解除映射
sleep(1);
if (0 > shmdt(addr))
{
perror("shmdt");
return -1;
}
//4. 销毁共享内存
if (0 > shmctl(shmid, IPC_RMID, NULL))
{
perror("shmctl");
return -1;
}
if (0 > semctl(semid, IPC_RMID, 0))
{
perror("semctl");
return -1;
}
return 0;
}