说明
本代码为jyy老师上课演示条件变量解决同步问题示例(本人只做记录与分享)
本人未使用老师封装的POSIX线程库, 直接在单文件中调试并注释
问题描述
有三类线程
T1 若干: 死循环打印<
T2 若干: 死循环打印>
T3 若干: 死循环打印_
任务:
对线程同步,使得屏幕打印出<><_
和_><>
的组合
状态机
代码
#include <pthread.h>
#include <iostream>
#include <assert.h>
#include <string>
#include <vector>
#define Lock(x) pthread_mutex_lock(x)
#define UnLock(x) pthread_mutex_unlock(x)
// 状态机的状态, 从1开始编号
enum { A = 1, B, C, D, E, F, };
// 构建状态机的
struct rule {
int from, ch, to;
};
std::vector<rule> rules = {
// <><
{A, '<', B},
{B, '>', C},
{C, '<', D},
// ><>
{A, '>', E},
{E, '<', F},
{F, '>', D},
// D是打印出一条鱼后停留的状态,
// 需要经过'_'到初始状态A, 重新打印鱼
{D, '_', A},
};
// 当前状态
int current_state = A;
pthread_mutex_t lk = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
/**
* 检查当前状态是否又ch这条出边
* 返回0表示无法根据ch转移到一个状态
*/
int next(char ch) {
// 检查ch是否是当前状态的出边
for (const auto& rule : rules) {
if (rule.from == current_state && rule.ch == ch) {
return rule.to;
}
}
return 0;
}
/**
* 检查同步条件是否满足
*/
static int can_print(char ch) {
return next(ch) != 0;
}
// 创建12个线程, 每4个打印同种字符
std::string charlib = ".<<<<<>>>>___";
void* fish_thread(void* arg) {
int id = *((int *)arg);
char role = charlib[id];
while (true) {
// 先上锁
Lock(&lk);
// 再检查条件变量
while (!can_print(role)) {
pthread_cond_wait(&cv, &lk);
}
putchar(role); // Not lock-protected
// 更新到下一个状态
current_state = next(role);
assert(current_state);
// 更新状态后可能会使得等待该条件的线程满足条件
pthread_cond_broadcast(&cv);
UnLock(&lk);
}
}
int main() {
std::vector<pthread_t> threads(charlib.size());
std::vector<int> pid(charlib.size());
for (int i = 0; i < charlib.size(); i++) {
pid[i] = i + 1;
pthread_create(&threads[i], nullptr, &fish_thread, &pid[i]);
}
for (int i = 0; i < charlib.size(); i++) {
pthread_join(threads[i], nullptr);
}
}