【Linux之进程间通信】
项目代码获取:https://gitee.com/chenshao777/linux-processes.git
(麻烦点个免费的Star哦,您的Star就是我的写作动力!)
08.信号量集
流程:
公共头文件:
#include
#include
#include
int semget(key_t key, int nsems, int semflg);
参数 | 含义 |
---|---|
key | 生成semid相关key值 |
nsems | 初始化信号集中信号的个数 |
semflg | 权限 |
返回值:成功返回信号集ID,失败返回-1
int semctl(int semid, int semnum, int cmd, ...);
参数 | 含义 |
---|---|
semid | 信号集ID |
semnum | 信号量编号(从0开始) |
cmd | 不同任务所需的命令参数 |
… | 根据cmd决定第四项是否需要 |
返回值:成功根据cmd返回不同值,失败返回-1
当cmd为 SETVAL 时,表示设置信号属性,则第四个参数类型为 union semun
union semun {
int val; /* 信号值 */
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) */
};
我们需要关心的主要是联合体中的第一个成员 val
比如,我们要初始化信号集中的第二个信号,将他的初始值初始化为0,代码如下:
/*初始化信号*/
union semun mysemun;
mysemun.val = 0;
//设置第2个信号(1)
semctl(semid, 1, SETVAL, mysemun);
int semop(int semid, struct sembuf *sops, size_t nsops);
参数 | 含义 |
---|---|
semid | 信号集ID |
sops | 信号操作结构体 |
nsops | 要操作的信号个数 |
返回值:成功返回0,失败返回-1
其中struct sembuf结构体成员如下:
unsigned short sem_num; /* 信号量编号 */
short sem_op; /* 信号操作(P分配或者V释放) */
short sem_flg; /* 阻塞操作 / 非阻塞操作 */
比如我们要分配第二个信号量,且阻塞操作
/*分配信号*/
//设置操作信号的方式(P分配或V释放)
struct sembuf sops;
sops.sem_num = 1; //要操作的信号量编号
sops.sem_flg = 0; //阻塞操作
sops.sem_op = -1; //分配资源 P操作
semop(semid, &sops, 1); // 1:操作的信号数为1
system("ipcs -s");
/*删除信号集*/
semctl(semid, 0, IPC_RMID);
实验说明:client进程先启动,但要等待server进程先运行起来,client进程才开始运行
通过信号机制实现
server.c
#include
#include
#include
#include
#include
#include
/*
通过信号灯同步两个非亲缘关系进程
client端先启动,等server端输出十条语句后client端才运行
*/
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 main(int argc, char *argv[])
{
/*初始化信号量集*/
int key, semid;
key = ftok("./a.c", 1);
//初始化一个有3个信号量的信号集
semid = semget(key, 3, IPC_CREAT | 0777);
if(semid < 0){
printf("server信号灯初始化失败!\n");
return -1;
}
printf("server信号灯初始化成功!,semid = %d\n", semid);
//查看信号集
system("ipcs -s");
/*初始化信号*/
union semun mysemun;
mysemun.val = 0;
//设置第2个信号(1)
semctl(semid, 1, SETVAL, mysemun);
/*打印十条语句*/
for(int i=0;i<10;i++){
printf("server\n");
}
/*分配信号*/
//设置操作信号的方式(P或V)
struct sembuf sops;
sops.sem_num = 1; //要操作的信号量编号
sops.sem_flg = 0; //阻塞操作
sops.sem_op = 1; //分配资源 V操作
semop(semid, &sops, 1); // 1:操作的信号数为1
return 0;
}
client.c
#include
#include
#include
#include
#include
#include
/*
通过信号灯同步两个非亲缘关系进程
client端先启动,等server端输出十条语句后client端才运行
*/
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 main(int argc, char *argv[])
{
/*初始化信号量集*/
int key, semid;
key = ftok("./a.c", 1);
//初始化一个有3个信号量的信号集
semid = semget(key, 3, IPC_CREAT | 0777);
if(semid < 0){
printf("client信号灯初始化失败!\n");
return -1;
}
printf("client信号灯初始化成功!,semid = %d\n", semid);
//查看信号集
system("ipcs -s");
/*初始化信号*/
union semun mysemun;
mysemun.val = 0;
//设置第2个信号(1)
semctl(semid, 1, SETVAL, mysemun);
/*分配信号*/
//设置操作信号的方式(P或V)
struct sembuf sops;
sops.sem_num = 1; //要操作的信号量编号
sops.sem_flg = 0; //阻塞操作
sops.sem_op = -1; //分配资源 P操作
semop(semid, &sops, 1); // 1:操作的信号数为1
/*休眠1秒,打印十条语句*/
sleep(1);
for(int i=0;i<10;i++){
printf("client\n");
}
/*删除信号集*/
semctl(semid, 0, IPC_RMID);
//查看信号集
system("ipcs -s");
return 0;
}