Linux进程通信——使用信号量

头文件:

#include <sys/ipc.h>

#include <sys/sem.h>

#include <sys/types.h>

函数: key_t ftok(const char *filename, int proj_id);
通过文件名和项目号获得System V IPC键值(用于创建消息队列、共享内存所用)
proj_id:项目号,不为0即可
返回:成功则返回键值,失败则返回-1

函数: int semget(key_t key, int nsems, int msgflg);
key:键值,当为IPC_PRIVATE时新建。
nsems:信号个数。
msgflg:标志。
IPC_CREAT:不存在则新建,否则打开;
IPC_EXCL:与IPC_CREAT一同使用时,只有在不存在时才创建,否则出错。
返回:成功则返回IPC标识符,出错返回-1

函数: int semop(int semid, struct sembuf *sops, unsigned nsops);
semid:通过semget获取
sops:指向待操作的信号灯结构体,原型如下:
struct sembuf{
unsigned short sem_num; //信号灯编号,从0开始
short sem_op; //为正数代表释放信号;为负代表获取信号
Short sem_flg; //操作的标识;IPC_NOWAIT:不阻塞;IPC_UNDO:程序结束时释放信号量
}
nsops:要操作的信号量数
返回:成功则返回共享内存起始地址,失败返回-1

函数: void semctl(int semid, int semnum, int cmd, union semun arg);
semid:通过semget获取
semnum:操作的信号灯编号
cmd:控制命令,如下:
GETPID:获取sempid
GETVAL:获取semval
SETVAL:设置semval
IPC_RMID:删除信号灯
arg:各个量使用与cmd设置有关
返回:成功返回与cmd相关的正数,错误返回-1

注意:信号量一旦创建就会一直存在系统中,直到手动删除或者重启系统。可以使用ipcs -s命令来查看系统存在的信号量。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/****************************************
*
* 使用信号量进行进程通信——进程1
* 该进程用于创建信号量
* 龙昌博客:http://www.xefan.com
*
****************************************/
#include <sys/types.h>
//书上说是用sys/ipc.h和sys/sem.h这两个头文件,但是我用了出错,
//而用linux/ipc.h和linux/sem.h却没问题
//#include <sys/ipc.h>
//#include <sys/sem.h>
#include <linux/sem.h>
#include <linux/ipc.h>
#include <errno.h>
#include <math.h>

int main(int argc, char *argv[])
{
int key, sid, pid;
union semun val;
val.val = 1;
key = ftok("tmp",10);
if ((sid = semget(key, 1, IPC_CREAT)) < 0)
{
perror("semget");
exit(-1);
}
printf("key: %d sid:%d\n", key, sid);

if ((semctl(sid, 0, SETVAL, val)) < 0)
{
perror("semctl");
exit(-1);
}
if ((semctl(sid, 0, GETVAL, val)) < 0)
{
perror("semctl");
exit(-1);
}
printf("sem_val:%d\n", val.val);

struct sembuf p_op, v_op;
p_op.sem_num = 0;
p_op.sem_op = -1;
//获取信号
if (semop(sid, &p_op, 1) < 0) //p op
{
perror("smeop");
exit(-1);
}
printf("father get the semaphore\n");
sleep(8);
printf("father release the senaphore\n");
v_op.sem_num = 0;
v_op.sem_op = 1;
v_op.sem_flg = 0;
//释放信号
if (semop(sid, &v_op, 1) < 0) //v op
{
perror("semop");
exit(-1);
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/****************************************
*
* 使用信号量进行进程通信——进程2
* 该进程用于获取信号量
* 龙昌博客:http://www.xefan.com
*
****************************************/
#include <sys/types.h>
//书上说是用sys/ipc.h和sys/sem.h这两个头文件,但是我用了出错,
//而用linux/ipc.h和linux/sem.h却没问题
//#include <sys/ipc.h>
//#include <sys/sem.h>
#include <linux/sem.h>
#include <linux/ipc.h>
#include <errno.h>
#include <math.h>

int main(int argc, char *argv[])
{
int key, sid, pid;
key = ftok("tmp",10);
if ((sid = semget(key, 1, IPC_CREAT)) < 0)
{
perror("semget");
exit(-1);
}
printf("key: %d sid:%d\n", key, sid);

struct sembuf p_op, v_op;
p_op.sem_num = 0;
p_op.sem_op = -1;
//p_op.sem_flg = 0;
if (semop(sid, &p_op, 1) < 0) //p op
{
perror("smeop");
exit(-1);
}
printf("father get the semaphore\n");
sleep(8);
printf("father release the senaphore\n");
v_op.sem_num = 0;
v_op.sem_op = 1;
v_op.sem_flg = 0;
if (semop(sid, &v_op, 1) < 0) //v op
{
perror("semop");
exit(-1);
}
return 0;
}

先运行进程1,再运行进程2查看效果