信号量又称为信号灯,它是用来协调不同进程间的数据对象的(进程间数据同步)。本质声,信号量是一个计数器,它用来记录对某个资源的存取状况。一般来说,为了获得共享资源,进程需要执行以下操作:
1.测试控制该资源的信号量
2.若此信号量的值为正,则允许进行使用该资源。进程将信号量减1
3.若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤1
4.当进程不再使用一个信号量控制的资源时,信号量值加1。若此时有进程正在睡眠等待此信号量,则唤醒此进程。
示例1.1
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define IPC_KEY 0x00001234
int sem_id = -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) */
};
/*
struct sembuf
{
unsigned short int sem_num; // semaphore number
short int sem_op; // semaphore operation
short int sem_flg; // operation flag
};
*/
int sem_p()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
semop(sem_id, &buf, 1);
}
int sem_v()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
semop(sem_id, &buf, 1);
}
int main(int argc, char *argv[])
{
union semun arg;
arg.val = 1;
sem_id = semget(IPC_KEY, 1, IPC_CREAT|0664); //赋予权限
if (sem_id < 0){
printf("semget error!!\n");
return -1;
}
semctl(sem_id, 0, SETVAL, arg);
while (1){
sem_p();
printf("test 1\n");
sleep(1);
sem_v();
}
semctl(sem_id, 0, IPC_RMID, NULL);
return 0;
}
示例1.2
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define IPC_KEY 0x00001234
int sem_id = -1;
int sem_p()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
semop(sem_id, &buf, 1);
}
int sem_v()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
semop(sem_id, &buf, 1);
}
int main(int argc, char *argv[])
{
sem_id = semget(IPC_KEY, 1, IPC_CREAT);
if (sem_id < 0){
printf("semget error!!\n");
return -1;
}
while (1){
sem_p();
printf("Test 2\n");
sleep(3);
sem_v();
}
return 0;
}
1.使用semget函数创建信号量
2.使用semctl中的SETVAL对信号量进行初始化
3.同步前使用semop对信号量进行检测及P操作(减1)
4.同步完成对信号量进行V操作(加1)
5.使用semctl中的IPC_RMID删除信号量
Linux下查看信号量:sudo ipcs -s
Linux删除信号量:ipcrm -s semid