信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信, 它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。
信号量的工作原理
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
描述
semctl() 在 semid 标识的信号量集上,或者该集合的第 semnum 个信号量上执行 cmd 指定的控制命令。 (信号量集合索引起始于零。 )根据 cmd 不同,这个函数有三个或四个参数。当有四个参数时,第四个参数的类型是 union。调用程序必须按照下面式方定义这个联合体:
union semun {
int val; // 使用的值
struct semid_ds *buf; // IPC_STAT、 IPC_SET 使用缓存区
unsigned short *array; // GETALL,、 SETALL 使用的数组
struct seminfo *__buf; // IPC_INFO(Linux特有) 使用缓存区
};
注意:该联合体没有定义在任何系统头文件中,因此得用户自己声明。 <Centos 下确实是
这样,但是UNIX下不同,不需要自己定义声明>
测试代码:
sem.h
#define __SEM__ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/sem.h> #include <sys/ipc.h> #include <string.h> #include <errno.h> #define KEY_PATH "." #define PROJECT_ID 88 int create_sem(int _semset_num); int init_sem(int _sem_id, int _which); int sem_p(int _sem_id, int _which); int sem_v(int _sen_id, int _which); int destroy_sem(int _sem_id); int show_sem_val(int _sem_id, int _sem_num); int get_sem(); #endif
sem.c
#include "sem.h" //if success ,retrun : id of a semaphore set. //else return -1. int create_sem(int semset_num) { int create_flag = IPC_CREAT | IPC_EXCL;//IPC_EXCL,如果key已经存在,直接返回,防ket重 复 key_t k = ftok(KEY_PATH, PROJECT_ID); return semget(k, semset_num, create_flag); } //if success, retunr : sem id,else return -1; //semset_num is return sem_set num int get_sem() { key_t k = ftok(KEY_PATH, PROJECT_ID); return semget(k, 0, 0); } //return 0 if success,else return -1 static int op_sem(int sem_id, int op, int which) { struct sembuf sem; memset(&sem, '\0', sizeof(sem)); sem.sem_num = which; sem.sem_op = okp; sem.sem_flg = 0; return semop(sem_id, &sem, 1/*sem num*/); } int init_sem(int sem_id, int which) { semun_t _semun; _semun.val = 1; int ret = semctl(sem_id, which, SETVAL, _semun); if (ret == -1){ //printf("init sem error : errno code is : %d\n",errno); return ret; } //printf("init sem success : errno code is : %d\n",errno); return ret; } int sem_p(int sem_id, int which) { int ret = op_sem(sem_id, -1, which); if (ret == 0){ //printf("P operator is success!, errno code is : %d\n", errno); } else{ //printf("P operator is failed!, errno code is : %d\n", errno); } return ret; } int sem_v(int sem_id, int which) { int ret = op_sem(sem_id, 1, which); if (ret == 0){ //printf("V operator is success!, errno code is : %d\n", errno); } else{ //printf("V operator is failed!, errno code is : %d\n", errno); } return ret; } int destroy_sem(int sem_id) { int ret = semctl(sem_id, 0, IPC_RMID, NULL); if (ret == -1){ //printf("destroy sem error\n"); return ret; } //printf("destroy sem success, errno code is : %d\n", errno); return ret; } //for debug int show_sem_val(int sem_id, int sem_num) { semun_t _semun; unsigned short *_sem_list = (unsigned short *)malloc(sizeof(unsigned short)*sem_num); if (NULL == _sem_list){ //printf("malloc error,errno code is : %d\n", errno); //return 1; } memset(_sem_list, '\0', sizeof(unsigned short)* sem_num); _semun.array = _sem_list; int ret = semctl(sem_id, 0, GETALL, _semun); if (ret == -1){ //printf("get sem error : errno code is : %d\n",errno); } else{ int i = 0; for (; i<sem_num; i++){ printf("sem[%d] is : %d\n", i, _semun.array[i]); } } free(_sem_list); _semun.array = NULL; return ret; }