信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。

 信号量的工作原理

由于信号量只能进行两种操作等待和发送信号,即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_STATIPC_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;
}