信号量(信号灯) -----//目的:实现共享内存的多个进程之间同步
目录
一、信号量的分类
二、P/V操作
三、信号量相关函数
1、创建或获取信号量
2、实现p/v操作
3、设置信号量的信息
概念
信号量(集)(semaphore),也叫信号灯(集)。它是不同进程间或一个给定进程内部不同线程间同步的机制。
一、信号量的分类
1》二值信号灯:
值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。
2》计数信号灯:
值在0到n之间。用来统计资代表源,其值可用资源数
二、P/V操作
1》p操作 ---变红
p操作也叫等待操作,是等待信号灯的值变为大于0,然后将其减1;
2》V操作 ---变绿
V操作也叫释放操作,用来唤醒等待资源的进程或者线程
三、信号量相关函数
1、创建或获取信号量
int semget(key_t key, int nsems, int semflg);
//参数1 ----- key
//参数2 ----- 信号量集合中信号灯的个数
//参数3 ----- 权限:信号灯集的访问权限,通常为IPC_CREAT | 0666
//返回值 ---- 成功:信号量的ID,失败:-1
例如:
int main(void)
{
key_t key;
int sem_id;
if((key = ftok("./",0xb)) < 0)
perr("ftok");
if((sem_id = semget(key,4,IPC_CREAT|0666)) < 0)
perr("semget");
return 0;
}
2、实现p/v操作
int semop(int semid, struct sembuf *sops, size_t nsops);
//参数1 ----- 信号量的ID
//参数2 ----- 结构体struct sembuf的指针
struct sembuf{
unsigned short sem_num; /* semaphore number 要操作的信号量的下标,从0开始 */
short sem_op; /* semaphore operation 1-v操作 -1 --p操作,0 --等待,直到信号灯的值变成0 */
short sem_flg; /* operation flags 一般为0, IPC_NOWAIT, SEM_UNDO */
}
//参数3 ----- 要操作的信号量的个数
//返回值----成功:0,失败:-1
//实现p操作
void sem_p(int semid,unsigned short num,int nsops)
{
struct sembuf buf = {num,-1,0};
if(semop(semid,&buf,nsops) < 0)
perr("semop");
}
//实现V操作
void sem_v(int semid,unsigned short num,int nsops)
{
struct sembuf buf = {num,1,0};
if(semop(semid,&buf,nsops) < 0)
perr("semop");
}
3、设置信号量的信息
int semctl(int semid, int semnum, int cmd, ...);
//参数1 ---- 信号量的ID
//参数2 ---- 要操作的信号量的编号
//参数3 ---- 选项:
GETVAL:获取某个指定的信号灯的值
SETVAL:设置某个指定的信号灯的值
IPC_RMID:从系统中删除信号灯集合
SETALL: 设置所有的信号灯的值
//变参 ----- 联合体:
union semun {
int val; /* cmd为SETVAL,则使用val */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* cmd为 GETALL, SETALL 则使用array*/
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
//返回值 ----成功:0,失败:-1
例如:
//给单个信号灯初始化
void sem_init(int semid,int num,int value)
{
union semun un;
un.val = value;
if(semctl(semid,num,SETVAL,un) < 0)
perr("semctl");
}
//给所有信号灯初始化
void sem_init_all(int semid,int num,unsigned short *val_arr)
{
union semun un;
un.array = val_arr;
if(semctl(semid,num,SETVALL,un) < 0)
perr("semctl");
}