1. 前驱 - 后继关系的进程控制(P92)
问题描述:多个进程需按特定顺序执行
解决方案:
- 每个前驱进程对应一个信号量,初始化为 0。
- 前驱进程完成后执行
V
操作,通知后继进程。 - 后继进程在开始前通过
P
操作等待所有前驱完成。
代码:(std=c++23 后同)
#include <iostream>
#include <semaphore>
#include <thread>
std::binary_semaphore a(0), b(0), c(0), d(0), e(0), f(0), g(0), h(0);
void S1() {
std::cout << "S1\n";
a.release();
b.release();
}
void S2() {
a.acquire();
std::cout << "S2\n";
c.release();
d.release();
}
void S3() {
b.acquire();
std::cout << "S3\n";
e.release();
}
void S4() {
c.acquire();
std::cout << "S4\n";
f.release();
}
void S5() {
d.acquire();
std::cout << "S5\n";
g.release();
}
void S6() {
f.acquire();
g.acquire();
e.acquire();
std::cout << "S6\n";
}
int main() {
std::jthread j1(S1), j2(S2), j3(S3), j4(S4), j5(S5), j6(S6);
return 0;
}
2. 父亲、儿子、女儿的同步(P113)
问题描述:父亲向盘子放水果(苹果或橘子),儿子取桔子,女儿取橘苹果,盘子一次只能放一个水果。
解决方案:
- 使用三个信号量:
empty
:表示盘子是否为空(初始为 1)。apple
和orange
:表示是否有对应水果可拿(初始为 0)。
- 父亲放水果前等待盘子为空,放入后通知对应孩子。
- 孩子取水果后释放盘子。
代码:
#include <cstddef>
#include <iostream>
#include <semaphore>
#include <thread>
std::binary_semaphore empty(1), apple(0), orange(0);
void father() {
for (size_t i = 0; i < 10; i++) {
bool is_apple = (i % 2 == 0);
empty.acquire();
if (is_apple) {
std::cout << "Father: produced apple\n";
apple.release();
} else {
std::cout << "Father: produced orange\n";
orange.release();
}
}
}
void son() {
for (size_t i = 0; i < 5; i++) {
orange.acquire();
std::cout << "Son: comsume orange\n";
empty.release();
}
}
void daughter() {
for (size_t i = 0; i < 5; i++) {
apple.acquire();
std::cout << "Daughter: comsume apple\n";
empty.release();
}
}
int main() {
std::jthread j1(father), j2(son), j3(daughter);
return 0;
}
3. 拥挤路段的控制(P119)
问题描述:限制路段同时通过的车辆数,左右均是两车道有来车,中间只能允许一辆车单向通行
解决方案:
- 使用三个信号量,lmut 和 rmut 保护各自的计数器,tmut 是桥的通行权
- 第一个能够上桥的抢过桥的通行权,然后增加该方向的计数。如果后来的同方向的发现计数大于 0 则可以跟着上桥
- 下桥的时候一样用 lmut 和 rmut 保护,最后一个下桥的恢复桥的通行权
代码:
#include <chrono>
#include <iostream>
#include <semaphore>
#include <thread>
int lc = 0, rc = 0;
std::binary_semaphore lmut(1), rmut(1), tmut(1);
void l_vehicle() {
// 1. 保证现在是这个方向了
lmut.acquire();
if (lc == 0) { tmut.acquire();} // 如果是第一个,就抢过桥的使用权
lc++;
lmut.release();
// 2. 开始行动
std::cout << "go from left\n";
std::this_thread::sleep_for(std::chrono::milliseconds(50));
// 3. 完成释放
lmut.acquire();
lc--;
if (lc == 0) { tmut.release(); } // 最后一辆车释放桥的使用权
lmut.release();
}
void r_vehicle() {
rmut.acquire();
if (rc == 0) { tmut.acquire(); }
rc++;
rmut.release();
std::cout << "go from right\n";
std::this_thread::sleep_for(std::chrono::milliseconds(50));
rmut.acquire();
rc--;
if (rc == 0) { tmut.release(); }
rmut.release();
}
int main() {
std::jthread j[] = {
std::jthread(r_vehicle), std::jthread(l_vehicle),
std::jthread(l_vehicle), std::jthread(l_vehicle),
std::jthread(r_vehicle), std::jthread(r_vehicle),
std::jthread(r_vehicle), std::jthread(l_vehicle),
std::jthread(r_vehicle),
};
return 0;
}