信号量又称为信号灯,它是用来协调不同进程间的数据对象的(进程间数据同步)。本质声,信号量是一个计数器,它用来记录对某个资源的存取状况。一般来说,为了获得共享资源,进程需要执行以下操作:
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