背景
某银行提供1个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅允许一位顾客使用。当营业员空闲时,通过叫号选取一位顾客,并为其服务。
关键点
-
信号量
PS1:服务窗口只有1个,所以不需要设置信号量
PS2:macOS不支持匿名信号量,不支持使用sem_init而改用sem_open
PS3:使用完使用Ctrl+C终止(csignal支持捕获按键)后,也需要清除匿名信号量,使用兼容性好的sem_unlink
- 取完号等待的人数
- 取号机子是否在使用(0,1互斥)
- 座位剩余数
-
pthread多线程
代码实现(C++)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
* @Author: MetaNetworks
* @Date: 2019-10-14 16:53:28
* @LastEditors: MetaNetworks
* @LastEditTime: 2019-10-14 23:06:45
* @Description: MetaNetworks' Code
*/
// 某银行提供1个服务窗口和10个供顾客等待的座位。
// 顾客到达银行时,若有空座位,则到取号机上领取一个号,
// 等待叫号。取号机每次仅允许一位顾客使用。当营业员空闲时,
// 通过叫号选取一位顾客,并为其服务。顾客和营业员的活动过程描述如下:
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
// MultiProcess
#include <pthread.h>
// Semaphore
#include <semaphore.h>
// Register Signal
#include <csignal>
//definition
#define CUSTOMERNUM 20
#define SEATSNUM 10
// 座位数
sem_t* seats;
// 取完号等待的人数
sem_t* wait_people;
// 互斥信息量,机子
sem_t* machine;
// 行为函数
void * customer(void *);
void * window(void *);
void sig_handler(int sig);
// 常量
int servedPeople = 0;
// 主函数
int main(int argc, char const *argv[]){
// 注册 Register
signal(SIGINT,sig_handler);
// 20 customers
pthread_t customers[CUSTOMERNUM];
// 1 window
pthread_t windows;
// initail
seats = sem_open("/seats",O_CREAT,0644,SEATSNUM);
// sem_mutex
machine = sem_open("/machine",O_CREAT,0644,1);
// waiting row
wait_people = sem_open("/waitPeople",O_CREAT,0644,0);
// bank
pthread_create(&windows,NULL,&window,NULL);
// customer
for (int i = 0; i < CUSTOMERNUM; i++)
{
pthread_create(&customers[i],NULL,&customer,NULL);
}
// wait for sub process
for (int i = 0; i < CUSTOMERNUM; i++)
{
pthread_join(customers[i],NULL);
}
pthread_join(windows,NULL);
return 0;
}
// 按下Ctrl+C后需要销毁
void sig_handler(int sig){
if (sig == SIGINT)
{
// destory semephrone
printf("\n销毁信号量\n");
sem_unlink("/seats");
sem_unlink("/machine");
sem_unlink("/waitPeople");
exit(0);
}
}
// show message in terminal
void * showMessage(char* words){
printf("%s\n",words);
return NULL;
}
void * customer(void *){
//showMessage("我是一名顾客");
sem_wait(seats);
sem_wait(machine);
// 取号
printf("客人:已取号\n");
sem_post(machine);
// 开始等待,通知有等待的人数
sem_post(wait_people);
// 起身,释放座位,接收服务
sem_post(seats);
printf("客人:离开\n");
return NULL;
}
void * window(void *){
//showMessage("我是一个窗口");
while (true)
{
sem_wait(wait_people);
// 服务
printf("银行:叫号\n");
// 叫号
servedPeople += 1;
printf("银行:已经为%d号顾客服务\n",servedPeople);
}
return NULL;
}
执行效果
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
客人:已取号
客人:已取号
客人:已取号
客人:离开
银行:叫号
客人:已取号
银行:已经为1号顾客服务
银行:叫号
银行:已经为2号顾客服务
银行:叫号
银行:已经为3号顾客服务
银行:叫号
银行:已经为4号顾客服务
客人:离开
客人:离开
客人:离开
客人:已取号
客人:离开
银行:叫号
客人:已取号
银行:已经为5号顾客服务
客人:已取号
客人:离开
银行:叫号
银行:已经为6号顾客服务
银行:叫号
银行:已经为7号顾客服务
客人:离开
客人:已取号
客人:已取号
银行:叫号
客人:离开
银行:已经为8号顾客服务
银行:叫号
银行:已经为9号顾客服务
客人:离开
客人:已取号
客人:离开
银行:叫号
银行:已经为10号顾客服务
客人:已取号
客人:离开
银行:叫号
客人:已取号
银行:已经为11号顾客服务
客人:离开
银行:叫号
银行:已经为12号顾客服务
客人:已取号
客人:离开
客人:已取号
银行:叫号
银行:已经为13号顾客服务
客人:已取号
客人:离开
银行:叫号
银行:已经为14号顾客服务
客人:已取号
客人:离开
客人:离开
银行:叫号
客人:已取号
银行:已经为15号顾客服务
银行:叫号
银行:已经为16号顾客服务
客人:离开
客人:已取号
银行:叫号
客人:已取号
客人:离开
客人:离开
银行:已经为17号顾客服务
银行:叫号
银行:已经为18号顾客服务
银行:叫号
银行:已经为19号顾客服务
客人:已取号
客人:离开
银行:叫号
银行:已经为20号顾客服务
^C
销毁信号量