0%

进程间通信方式之信号量

信号量(semaphore)它是一个计数器,可以用来控制多个进程对共享资源的访问。

一、概念

      信号量(semaphore)它是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此主要作为进程间以及同一进程内不同线程之间的同步手段。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

特点

  • 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
  • 信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作
  • 每次对信号量的PV操作不仅限于对信号量值加1或减1,而且可以加减任意正整数
  • 支持信号量组

二、实现

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include<stdio.h>
#include<stdlib.h>
#include<sys/sem.h>

union semun {
int val; /*for SETVAL*/
struct semid_ds *buf;
unsigned short *array;
};

int init_sem(int sem_id, int value) {
union semun tmp;
tmp.val = value;
if(semctl(sem_id, 0, SETVAL, tmp) == -1) {
perror("Init Semaphore Error");
return -1;
}
return 0;
}

// P操作:若信号量值为1,获取资源并将信号量值-1;若信号量值为0,进程挂起等待
int sem_p(int sem_id) {
struct sembuf sbuf;
sbuf.sem_num = 0; /*序号*/
sbuf.sem_op = -1; /*P操作*/
sbuf.sem_flg = SEM_UNDO;

if(semop(sem_id, &sbuf, 1) == -1) {
perror("P operation Error");
return -1;
}
return 0;
}

// V操作:释放资源并将信号量值+1;如果有进程正在挂起等待,则唤醒它们
int sem_v(int sem_id) {
struct sembuf sbuf;
sbuf.sem_num = 0; /*序号*/
sbuf.sem_op = 1; /*V操作*/
sbuf.sem_flg = SEM_UNDO;

if(semop(sem_id, &sbuf, 1) == -1) {
perror("V operation Error");
return -1;
}
return 0;
}

int del_sem(int sem_id) {
union semun tmp;
if(semctl(sem_id, 0, IPC_RMID, tmp) == -1) {
perror("Delete Semaphore Error");
return -1;
}
return 0;
}


int main() {
int sem_id; // 信号量集ID
key_t key;
pid_t pid;

// 获取key值
if((key = ftok(".", 'z')) < 0) {
perror("ftok error");
exit(1);
}

// 创建信号量集,其中只有一个信号量
if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1) {
perror("semget error");
exit(1);
}

// 初始化:初值设为0资源被占用
init_sem(sem_id, 0);

if((pid = fork()) == -1) {
perror("Fork Error");
} else if(pid == 0) {
sleep(2);
printf("Process child: pid=%d\n", getpid());
sem_v(sem_id); /*释放资源*/
} else {
sem_p(sem_id); /*等待资源*/
printf("Process father: pid=%d\n", getpid());
sem_v(sem_id); /*释放资源*/
del_sem(sem_id); /*删除信号量集*/
}
return 0;
}