系列文章目录
进程间通信(零)——说明
进程间通信(一)——管道
进程间通信(二)——信号
进程间通信(三)——共享内存
进程间通信(四)——信号量
文章目录
一、信号量的概念
1、基本概念
信号量(灯),是替代互斥锁的另一种概念,用于解决多线程间同步和互斥,特别是访问临界资源时的同步访问。
NOTE:信号量本身和信号并没有什么特殊的交集
2、调用逻辑
信号量很像一个“开关”,n表示可用资源的数量,一共有3种情况:
- n>0 资源可用,数量为n
- n=0 资源被占用,当前可用资源数量为0
- n<0 资源被占用,当前可用资源数量为-n
信号量的操作有"P"、"V"操作 - P操作 减法操作,资源数量value会-1
- V操作 加法操作,资源数量value会+1
二、共享内存调用
API
函数 | 说明 |
---|---|
sem_init() | 初始化信号量 |
sem_wait() | 加锁 |
sem_post() | 解锁 |
sem_destroy() | 销毁信号量 |
1.初始化信号量
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
参数
key 键值,和共享内存的方式一样
nsems 信号量的数量,设置为1
semflg 位掩码,IPC_CTEAT、IPC_EXCL等
返回值:
成功 —— semid 失败 —— -1
2.PV操作
2.1 结构体
struct sembuf
{
unsigned short sem_num; /* semaphore number*/
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
}
说明
sem_num 信号灯下标
sem_op PV操作标志
如果是正数,就是V操作
如果是负数,就是P操作
Sem_flg 是否阻塞
0 代表阻塞
IPC_NOWAIT 不阻塞
2.2 API
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned nsops);
int semtimedop(int semid, struct sembuf *sops, size_t nsops,
const struct timespec *timeout);
参数:
semid 信号集ID号 (semget的返回值)
sops 数组
nsops 数组的大小(个数)
timeout 时间参数,为NULL时,semtimedop()和semop()没有区别。
返回值:
成功 —— 0 错误 —— 1
3.控制信号量
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
参数
semId 信号量集ID号
senum 某个信号灯的下标
cmd 命令
SETVAL 设置value
GETVAL 得到value
IPC_RMID 删除信号灯集(整个)
3.1 结构体
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
};
struct semid_ds
{
struct ipc_perm sem_perm; /* Ownership and permissions */
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned long sem_nsems; /* No. of semaphores in set */
};
struct ipc_perm
{
key_t __key; /* Key supplied to semget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};
3.2 设置信号量
当cmd的值是 SETVAL时
union semun us;
us.val = 5;
semctl(semid,0,SETVAL,us,NULL);
3.3 获取信号量信息
因为每次操作资源时,如果某个资源经过V操作,已经是6,如果只执行了2此P操作6-2=4,即使进/线程完全结束,资源仍然是锁定状态,我们最好先确认value的值。
当cmd的值是 GETVAL时
value = semctl(semid,0,GETVAL,NULL);
3.4 删除信号量
当cmd的值是 IPC_RMID时
semctl(semid,0,IPC_RMID,NULL);