信号灯也叫信号量,它能够用来同步进程的动作,不能传输数据。它的应用场景就像红绿灯,控制各进程使用共享资源的顺序。Posix无名信号灯用于线程同步, Posix有名信号灯,System V 信号灯。本章讨论用于进程同步的System V信号灯。
信号灯相当于一个值大于或等于0计数器,信号灯值大于0,进程就可以申请资源,信号灯值-1,如果信号灯值为0,一个进程还想对它进行-1,那么这个进程就会阻塞,直到信号灯值大于1。
使用System V信号灯的步骤如下:
1.使用semget()创建或打开一个信号灯集。
2.使用semctl()初始化信号灯集,。
3.使用semop()操作信号灯值,即进行 P/V操作。
P操作:申请资源,申清完后信号灯值-1;
V操作:释放资源,释放资源后信号灯值+1;
常用的API如下:
semget()
:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
函数功能:创建新信号灯集或获取一个创建好的信号灯集。
参数含义:
key:通过ftok()获取的key值;
nsems:指定信号灯集合中信号灯的数量;
semflg:权限掩码,指定IPC_CREAT为如果没有则创建该信号灯集,指定IPC_EXCL为如果存 在返回错误。
返回值:成功返回信号灯集标识符id,失败返回-1,
semctl()
:初始化信号灯集合
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, .../* union semun arg*/);
参数含义:
semid:信号灯集标识符;
semnum:要操作的集合中的信号灯编号
cmd:执行的操作 SETVAL IPC_RMID
arg :cmd指定SETVAL命令后由此参数向集合中的单个信号量赋值。
semop()
:在信号量上执行一个或多个操作。
#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; /信号量索引/
short sem_op; /* 执行的操作,+1或-1 /
short sem_flg; / ,阻塞0,不阻塞IPC_NOWAIT */
}
nsops:数组大小,最小是1。
返回值:成功返回0,失败返回-1。
实验代码在shm_sem/目录下:路径为:11_Linux系统开发进阶\Linux系统编程_章节使用资料。
write进程向共享内存写数据,read进程从共享内存读数据,使用信号灯同步,先写再读,read进程读完阻塞,等待write进程将S_READ信号进行V操作。
信号灯相关函数在“sem.h”:
#include <sys/types.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <errno.h>
#define S_READ 0
#define S_WRITE 1
union semun
{
int value;
};
/*声明两种操作方式*/
struct sembuf sop[2];
/*
* P操作,申请资源,信号量值-1
*/
void p_ipc_sem(int index,int