目录
信号量/灯
信号量-P/V操作
Posix 信号量
信号量初始化 – sem_init
信号量 – P / V 操作
System V IPC - 信号灯
System V IPC - 信号灯特点
System V信号灯使用步骤
信号灯创建/打开 – semget
信号灯初始化 – semctl
信号灯集初始化 - 示例
信号灯P/V操作 – semop
信号灯操作 – sembuf
笔记
信号量代表某一类资源,其值表示系统中该资源的数量
信号量是一个受保护的变量,只能通过三种操作来访问
初始化
P操作(申请资源)
V操作(释放资源)
P(S) 含义如下:
if (信号量的值大于0) {
申请资源的任务继续运行;
信号量的值减一;
}
else { 申请资源的任务阻塞;}
V(S) 含义如下:
信号量的值加一;
if (有任务在等待资源) {
唤醒等待的任务,让其继续运行
}
posix中定义了两类信号量:
无名信号量(基于内存的信号量,linux仅支持线程同步)
有名信号量
pthread库常用的信号量操作函数如下:
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem); // P操作
int sem_post(sem_t *sem); // V操作
#include
int sem_init(sem_t *sem, int pshared, unsigned int val);
成功时返回0,失败时EOF
sem 指向要初始化的信号量对象
pshared 0 – 线程间 1 – 进程间
val 信号量初值
#include
int sem_wait(sem_t *sem); P操作
int sem_post(sem_t *sem); V操作
成功时返回0,失败时返回EOF
sem 指向要操作的信号量对象
信号灯也叫信号量,用于进程/线程同步或互斥的机制
信号灯的类型
Posix 无名信号灯
Posix有名信号灯
System V 信号灯
信号灯的含义
计数信号灯
System V 信号灯是一个或多个计数信号灯的集合
可同时操作集合中的多个信号灯
申请多个资源时避免死锁
打开/创建信号灯 semget
信号灯初始化 semctl
P/V操作 semop
删除信号灯 semctl
#include
#include
int semget(key_t key, int nsems, int semflg);
成功时返回信号灯的id,失败时返回-1
key 和消息队列关联的key IPC_PRIVATE 或 ftok
nsems 集合中包含的计数信号灯个数
semflg 标志位 IPC_CREAT|0666 IPC_EXCL
#include
#include
int semctl(int semid, int semnum, int cmd, …);
成功时返回0,失败时返回EOF
semid 要操作的信号灯集id
semnum 要操作的集合中的信号灯编号
cmd 执行的操作 SETVAL IPC_RMID
union semun 取决于cmd
要求:假设信号灯集合中包含两个信号灯;
第一个初始化为2,第二个初始化为0
union semun myun;
myun.val = 2;
if (semctl(semid, 0, SETVAL, myun) < 0) {
perror(“semctl”); exit(-1);
}
myun.val = 0;
if (semctl(semid, 1, SETVAL, myun) < 0) {
perror(“semctl”); exit(-1);
}
#include
#include
int semop(int semid, struct sembuf *sops, unsigned nsops);
成功时返回0,失败时返回-1
semid 要操作的信号灯集id
sops 描述对信号灯操作的结构体(数组)
nsops 要操作的信号灯的个数
struct sembuf
{
short sem_num;
short sem_op;
short sem_flg;
};
semnum 信号灯编号
sem_op -1:P操作 1:V操作
sem_flg 0 / IPC_NOWAIT
信号灯/信号量(semaphore)
概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的
PV操作概念:
生产者和消费者场景
P(S) 含义如下:
if (信号量的值大于0) {
申请资源的任务继续运行;
信号量的值减一;
} else {
申请资源的任务阻塞;
}
V(S) 含义如下:
信号量的值加一;
if (有任务在等待资源) {
唤醒等待的任务,让其继续运行
}
三种信号灯:
Posix 有名信号灯
Posix 无名信号灯 (linux只支持线程同步)
System V 信号灯
Posix 有名信号灯和无名信号灯使用:
有名信号灯打开:
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);
参数:
name:name是给信号灯起的名字
oflag:打开方式,常用O_CREAT
mode:文件权限。常用0666
value:信号量值。二元信号灯值为1,普通表示资源数目
信号灯文件位置:/dev/shm
有名信号灯关闭
int sem_close(sem_t *sem);
有名信号灯的删除
int sem_unlink(const char* name);
无名信号灯初始化
int sem_init(sem_t *sem, int shared, unsigned int value);
参数:
sem:需要初始化的信号灯变量
shared: shared指定为0,表示信号量只能由初始化这个信号量的进程使用,不能在进程间使用,linux 不支持进程间同步。
Value:信号量的值
无名信号灯销毁
int sem_destroy(sem_t* sem);
信号灯P操作
int sem_wait(sem_t *sem);
获取资源,如果信号量为0,表示这时没有相应资源空闲,那么调用线程就将挂起,直到有空闲资源可以获取
信号灯V操作
int sem_post(sem_t *sem);
释放资源,如果没有线程阻塞在该sem上,表示没有线程等待该资源,这时该函数就对信号量的值进行增1操作,表示同类资源多增加了一个。如果至少有一个线程阻塞在该sem上,表示有线程等待资源,信号量为0,这时该函数保持信号量为0不变,并使某个阻塞在该sem上的线程从sem_wait函数中返回
注意:编译posix信号灯需要加pthread动态库。
System V 信号灯使用:
int semget(key_t key, int nsems, int semflg);
功能:创建/打开信号灯
参数:key:ftok产生的key值(和信号灯关联的key值)
nsems:信号灯集中包含的信号灯数目
semflg:信号灯集的访问权限,通常为IPC_CREAT |0666
返回值:成功:信号灯集ID ; 失败:-1
int semop ( int semid, struct sembuf *opsptr, size_t nops);
功能:对信号灯集合中的信号量进行P - V操作
参数:semid:信号灯集ID
struct sembuf {
short sem_num; // 要操作的信号灯的编号
short sem_op; // 1 : 释放资源,V操作
// -1 : 分配资源,P操作
short sem_flg; // 0(阻塞),IPC_NOWAIT, SEM_UNDO
};//对某一个信号灯的操作,如果同时对多个操作,则需要定义这种结构体数组
nops: 要操作的信号灯的个数 ,1个
返回值:成功 :0 ; 失败:-1
int semctl ( int semid, int semnum, int cmd…/*union semun arg*/);
功能:信号灯集合的控制(初始化/删除)
参数:semid:信号灯集ID
semnum: 要操作的集合中的信号灯编号
cmd:
GETVAL:获取信号灯的值,返回值是获得值
SETVAL:设置信号灯的值,需要用到第四个参数:共用体
IPC_RMID:从系统中删除信号灯集合
返回值:成功 0 ; 失败 -1