1、概念
多个程序同时访问一个共享资源一般是不允许的,为了避开这个事件而引发的一系列问题,我们需要一种方式,通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。
信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。
2、使用说明
进程在进行v操作的时候,如果信号量中的“量”小于0,则进程睡眠阻塞。
进程在进程 p操作的时候,对应的信号量进行“量”的加操作。
3、相关函数
3.1创建信号量:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
//功能:返回与参数key关联的系统V信号量标识符,它可用于获取先前创建的信号量集的标识符
//返回:如果成功,返回值 将是信号量集标识符(非负整数),否则返回-1,同时返回errno指出错误
参数:
- key:主键,系统根据主键建立
- nsems:信号量集中,设置多少个具体信号量
- mode:一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。
3.2打开信号量
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
参数:
- semid:信号量号
- sops:结构体
struct sembuf{
unsigned short sem_num; // 除非使用一组信号量,否则它为0
short sem_op; 信号量增量,一个是-1(P等待),一个是+1(V发送信号)
short sem_flg; 属性,通常为SEM_UNDO
};
- nsops: 一般是1,操作一次
返回值:
- 0成功,-1失败
3.3 信号量操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
//返回:0成功,-1失败
参数:
- semid: 信号量号
- semnum:信号量集下标
- cmd:IPC_IPC_RMID删除
- 可变参数部分根据具体其它cmd来选择
可能的cmd是:
4、完整示例
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
int main(void)
{
// 键 信号量个数 IPC_CREAT没有则创建
int semid = semget(1234, 1, 0664 | IPC_CREAT);//创建信号量
if(semid < 0){
perror("信号量创建失败:");
exit(1);
}
struct sembuf sem;
sem.sem_num = 0;//当前信号量
sem.sem_flg = SEM_UNDO;//默认操作,即没有量则阻塞
sem.sem_op = -3;
while(1){
//做V操作,获取信号量
semop(semid, &sem, 1);
printf("helloworld\n");
}
//删除 semid 当前 删除 值
semctl(semid, 0, IPC_RMID, 0);
return 0;
}
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/ipc.h>
int main(void)
{
//
int semid=semget(1234,1,0);
if(semid<0)
{
perror("信号量创建失败!");
exit(1);
}
struct sembuf sem;
sem.sem_num=0;
sem.sem_flg=SEM_UNDO;
sem.sem_op=1;
while(1)
{
getchar();
semop(semid,&sem,1);
//printf("helloworld\n");
}
semctl(semid,0,IPC_RMID,0);
return 0;
}