Linux中的信号量
目录
信号量概念
定义
操作
类型
应用
信号量封装
一、创建信号量
头文件
函数原型
参数说明
返回值
示例
二、设置信号量初始值
头文件
函数原型
参数解释
返回值
示例
三、信号量的P操作
头文件
函数原型
参数解释
返回值
示例
四、信号量的V操作
示例
信号量概念
定义
信号量是一种用于多进程 / 线程同步的整数变量,用于控制对共享资源的访问。凡是遇到内存操作就可以实现加锁。
操作
P 操作:信号量值减 1,若值小于 0 则进程阻塞,否则继续执行。
V 操作:信号量值加 1,若有进程阻塞则唤醒一个。
类型
二进制信号量:值为 0 或 1,用于互斥访问。
计数信号量:值为非负整数,控制多资源访问。
应用
互斥访问:确保同一时间只有一个进程 / 线程访问共享资源。
资源管理:控制对多个相同资源的并发访问。
进程同步:保证进程或线程按顺序执行。
信号量封装
1、创建/获取信号量
2、设置初始值,一般为1
3、P操作
4、V操作
一、创建信号量
semctl
是一个在 Unix 和类 Unix 系统中用于控制信号量集的系统调用函数。
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型
int semget(key_t key, int nsems, int semflg);
参数说明
key
:唯一标识。
nsems
:要创建的信号量集中信号量的数量。
semflg
:标志位,用于指定创建信号量集的权限和其他选项。它可以是以下值的组合:
IPC_CREAT
:如果信号量集不存在,则创建它。
IPC_EXCL
:与IPC_CREAT
一起使用,如果信号量集已经存在,则返回错误。权限标志(如
0666
):指定信号量集的访问权限。
返回值
成功时,返回一个非负整数,即信号量集的标识符(semaphore identifier),后续的信号量操作将使用这个标识符。
失败时,返回 -1,并设置 errno
以指示错误类型。
示例
int sem_create(key_t key, int num_sems)
{int res = 0;res = semget(key, num_sems, IPC_CREAT | 0666);if (res < 0){perror("semget error");}return res;
}
二、设置信号量初始值
semctl
是类 Unix 系统中用于控制信号量集的一个系统调用,借助它能够对信号量集进行多种操作,例如设置信号量的值、获取信号量的值、删除信号量集等。
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型
int semctl(int semid, int semindex, int cmd, ...);
参数解释
semid
:信号量集的标识符,由semget
函数返回,用于指定要操作的信号量集。
semindex
:为第几个信号量设置值。
cmd
:要执行的命令,常见的命令如下:
SETVAL
:把单个信号量的值设置为传入的参数值。
GETVAL
:获取单个信号量的值。
SETALL
:设置信号量集中所有信号量的值。
GETALL
:获取信号量集中所有信号量的值。
IPC_RMID
:删除信号量集。
...
:这是可选参数,依据cmd
的不同而有所不同。在使用SETVAL
或SETALL
时,需要传入对应的参数值。通常使用union semun
类型的变量来传递该参数,union semun
的定义如下: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) */ };
返回值
成功时,依据 cmd
的不同返回不同的值。例如,GETVAL
命令返回信号量的值,IPC_RMID
命令成功时返回 0。
失败时,返回 -1,并设置 errno
以指示错误类型。
示例
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) */
};int sem_setval(int semid, int semindex, int val)
{union semun arg;arg.val = val;int res = semctl(semid, semindex, SETVAL, arg);if (res < 0){perror("semctl error");}return res;
}
三、信号量的P操作
semop
是类 Unix 系统中用于对信号量集进行操作的系统调用,它允许进程原子性地对一个或多个信号量进行改变,常用于实现进程间的同步和互斥。
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型
int semop(int semid, struct sembuf *sops, size_t nsops);
参数解释
semid
:信号量集的标识符,由semget
函数返回,用于指定要操作的信号量集。
sops
:一个指向struct sembuf
类型数组的指针,struct sembuf
结构体定义了对信号量的具体操作,其结构如下:struct sembuf {unsigned short sem_num; // 信号量集中信号量的编号,从 0 开始short sem_op; // 对信号量的操作值short sem_flg; // 操作标志 };
sem_num
:指定要操作的信号量在信号量集中的编号。
sem_op
:表示对信号量的操作值,有以下几种情况:若
sem_op
为正数,则表示释放相应数量的资源,信号量的值会增加sem_op
。若
sem_op
为负数,则表示请求相应数量的资源,信号量的值会减少sem_op
。若信号量当前值小于|sem_op|
,则进程可能会阻塞,具体取决于sem_flg
。若
sem_op
为 0,则表示等待信号量的值变为 0。
sem_flg
:操作标志,常用的标志有:
IPC_NOWAIT
:若操作不能立即执行,则不阻塞,直接返回错误。
SEM_UNDO
:当进程终止时,系统会自动撤销该进程对信号量的操作。
nsops
:sops
数组中元素的个数,即要执行的操作数量。
返回值
成功时,返回 0。
失败时,返回 -1,并设置 errno
以指示错误类型。
示例
// 3、信号量的P操作
int sem_p(int semid, int semindex)
{int res = 0;struct sembuf buf = { semindex,-1,SEM_UNDO };res = semop(semid, &buf, 1);if (res < 0){perror("sem_p error");}return res;
}
四、信号量的V操作
v操作唯一的变化就是从-1变成+1
示例
// 4、信号量的V操作
int sem_v(int semid, int semindex)
{int res = 0;struct sembuf buf = { semindex,1,SEM_UNDO };res = semop(semid, &buf, 1);if (res < 0){perror("sem_p error");}return res;
}