操作系统进程相关:用PV操作解决生产者消费者问题。
问题描述
当进程并发执行时,如果对进程访问的共享变量不加限制,就会产生“与时间有关”的错误。为了防止这类错误,系统必须用同步机构来控制进程对共享变量的访问。一般说,同步机构是由若干条同步原语所组成。本实验要求模拟P、V操作实现同步机构,且用P、V操作解决生产者—消费者问题。
参考
代码实现
1 |
|
2 |
|
3 |
|
4 | using namespace std; |
5 |
|
6 | |
7 | // 进程控制块PCB |
8 | struct PNode { |
9 | string name; // 进程名 |
10 | string state; // 状态 |
11 | string reason; // 等待原因 |
12 | int breaking; // 断点 |
13 | } produce, consume, *run, *ready; // 生产者进程、消费者进程、当前运行进程、当前就绪进程 |
14 | |
15 | // 初始化数据结构 |
16 | int s1 = 10, s2 = 0, PC; // 两个信号量,程序计数器PC |
17 | int PA[5]; // PA[i]存放生产者程序中的一条模拟指令执行的入口地址 |
18 | int SA[5]; // SA[i]存放消费者程序中的一条模拟指令执行的入口地址 |
19 | int IN = 0, OUT = 0; // 进出缓冲期的位置 |
20 | char product, X; // 生产的产品、消费的产品 |
21 | char B[10]; // 缓冲器 |
22 | |
23 | // 初始化程序 |
24 | void init() { |
25 | for(int i=0; i<5; i++) { |
26 | PA[i] = i; |
27 | SA[i] = i; |
28 | } |
29 | produce.name = "Produce"; |
30 | produce.state = "Ready"; // 生产者就绪 |
31 | produce.breaking = 0; // 断点为0 |
32 | consume.name = "Consume"; |
33 | consume.state = "Ready"; // 消费者就绪 |
34 | consume.breaking = 0; // 断点为0 |
35 | PC = 0; |
36 | } |
37 | |
38 | // 处理机调度程序 |
39 | void schedule() { |
40 | if(produce.state=="Ready" && consume.state=="Ready") { |
41 | srand((unsigned)time(NULL)); |
42 | int a = rand() % 2; // 随机数 0或1 |
43 | if(a == 1) { |
44 | run = &produce; // 生产者进程运行 |
45 | ready = &consume; // 消费者进程就绪 |
46 | }else { |
47 | run = &consume; // 消费者进程运行 |
48 | ready = &produce; // 生产者进程就绪 |
49 | } |
50 | }else if(produce.state=="Ready" && consume.state=="Wait") { |
51 | run = &produce; // 生产者进程运行 |
52 | ready = &consume; // 消费者进程就绪 |
53 | }else if(produce.state=="Wait" && consume.state=="Ready") { |
54 | run = &consume; // 消费者进程运行 |
55 | ready = &produce; // 生产者进程就绪 |
56 | } |
57 | PC = run->breaking; // 设置断点保护现场 |
58 | } |
59 | |
60 | // 处理器执行指令程序 |
61 | void perform() { |
62 | if(run->name == "Produce") { // 当前生产者程序在运行 |
63 | int j = PA[PC++]; // 生产者程序指令执行的入口地址 |
64 | switch(j) { |
65 | case 0: cout << "生产!请输入一个字符 > "; cin >> product; break; // produce |
66 | case 1: // P(s1) |
67 | s1--; |
68 | if(s1 < 0) { |
69 | run->state = "Wait"; |
70 | run->reason = "s1"; |
71 | cout << "生产者等待原因: " << run->reason << endl; |
72 | }else run->state = "Ready"; |
73 | break; |
74 | case 2: // PUT |
75 | B[IN] = product; |
76 | IN = (IN + 1) % 10; |
77 | cout << "缓冲器内容: "; |
78 | for(int i=0; i<10; i++) |
79 | cout << B[i] << " "; |
80 | cout << endl; |
81 | break; |
82 | case 3: // V(s2) |
83 | s2++; |
84 | if(s2 <= 0) ready->state = "Ready"; |
85 | else run->state = "Ready"; |
86 | break; |
87 | case 4: PC = 0; break; // GOTO 0 |
88 | } |
89 | run->breaking = PC; // 设置断点保护现场 |
90 | }else { // 当前消费者程序在运行 |
91 | int j = SA[PC++]; // 消费者程序指令执行的入口地址 |
92 | switch(j) { |
93 | case 0: // P(s2) |
94 | s2--; |
95 | if(s2 < 0) { |
96 | run->state = "Wait"; |
97 | run->reason = "s1"; |
98 | cout << "消费者等待原因: " << run->reason << endl; |
99 | }else run->state = "Ready"; |
100 | break; |
101 | case 1: X = B[OUT]; OUT = (OUT + 1) % 10; break; // GET |
102 | case 2: // V(s1) |
103 | s1++; |
104 | if(s1 <= 0) ready->state = "Ready"; |
105 | else run->state = "Ready"; |
106 | break; |
107 | case 3: cout << "消费!显示消费的结果 > " << X << endl; break; // consume |
108 | case 4: PC = 0; break; // GOTO 0 |
109 | } |
110 | run->breaking = PC; // 设置断点保护现场 |
111 | } |
112 | } |
113 | |
114 | int main() { |
115 | init(); // 初始化程序 |
116 | cout << "**用PV操作解决生产者消费者问题**" << endl; |
117 | for(int i=0; i<DO_NUM; i++) { |
118 | schedule(); // 处理机调度 |
119 | perform(); // 处理机执行指令 |
120 | } |
121 | return 0; |
122 | } |