C++多线程 | 用 condition_variable 实现数字和字母交替打印
本文演示了如何使用C++中的互斥锁(mutex)和条件变量(condition_variable)实现两个线程交替打印数字和字母。通过一个全局标志位(turn)控制线程执行顺序,当线程不满足执行条件时调用cv.wait()挂起,执行完后修改标志位并通过cv.notify_all()唤醒对方线程。文章详细讲解了同步机制的核心思路,提供了完整代码示例,并分析了常见错误和扩展思考方向。这种线程同步模式适
在多线程编程中,线程之间的同步与通信是非常经典的主题。
今天我们用一个小例子来演示:两个线程交替打印数字和字母,比如:
Thread 1: 1 Thread a: a Thread 1: 2 Thread a: b ...
这看似简单的问题,其实包含了 线程同步、条件变量、互斥锁 等核心知识点。
🧩 一、需求分析
我们希望有两个线程:
-
线程1打印数字:
1 2 3 4 -
线程2打印字母:
a b c d
并且它们要交替执行,不能乱序。
为此,我们需要一个控制变量 turn 来表示当前该谁打印:
-
当
turn == true时,轮到数字线程; -
当
turn == false时,轮到字母线程。
⚙️ 二、核心思路
-
用一个全局互斥锁
mutex mtx保证共享资源安全。 -
用一个条件变量
condition_variable cv实现线程的等待与唤醒。 -
每个线程在自己的循环中判断:
-
如果轮到自己,执行打印;
-
否则调用
cv.wait()挂起,等待另一个线程唤醒。
-
-
当打印结束后,修改
turn并调用cv.notify_all()通知对方线程继续执行。
💻 三、完整代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
int num = 1; // 数字打印上限
char c = 'a'; // 字母起始
mutex mtx; // 互斥锁
condition_variable cv; // 条件变量
bool turn = true; // true 表示轮到数字线程,false 表示轮到字母线程
void printNum(int id) {
while (true) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, []() { return turn; }); // 等待轮到自己
if (num > 4) {
turn = false;
cv.notify_all();
break;
}
cout << "Thread " << id << ": " << num << endl;
++num;
turn = false; // 轮到字母线程
cv.notify_all(); // 唤醒对方
}
}
void printChar(char id) {
while (true) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, []() { return !turn; }); // 等待轮到自己
if (c > 'd') {
turn = true;
cv.notify_all();
break;
}
cout << "Thread " << id << ": " << c << endl;
++c;
turn = true; // 轮到数字线程
cv.notify_all(); // 唤醒对方
}
}
int main() {
thread t1(printNum, 1);
thread t2(printChar, 'a');
t1.join();
t2.join();
cout << "Done." << endl;
return 0;
}
📊 四、运行结果
Thread 1: 1 Thread a: a Thread 1: 2 Thread a: b Thread 1: 3 Thread a: c Thread 1: 4 Thread a: d Done.
🧠 五、关键点讲解
| 关键点 | 说明 |
|---|---|
std::mutex |
保证同一时刻只有一个线程能访问共享变量 |
std::unique_lock |
可与条件变量配合使用的加锁机制 |
cv.wait(lock, predicate) |
当条件 predicate 不满足时,线程会阻塞;当被 notify 唤醒时,会重新检查条件 |
cv.notify_all() |
唤醒所有等待线程(通常两个线程用 notify_one() 也可) |
turn 标志变量 |
决定当前哪个线程可以执行 |
🧩 六、常见错误分析
| 错误现象 | 原因 |
|---|---|
| 程序卡死不退出 | cv.wait 条件写反,线程永远等不到唤醒 |
| 输出错乱 | 未加互斥锁或 turn 更新不及时 |
| 只打印一半 | 忘记在退出前 notify_all() 导致对方线程永久阻塞 |
🚀 七、扩展思考
这个例子演示了两个线程交替打印。
如果你想进一步练习,可以尝试:
-
扩展为 三个线程轮流打印(例如 1 → 2 → 3 → 1...);
-
使用
std::atomic<int>管理状态; -
用 信号量(semaphore) 实现同样逻辑;
-
用 条件变量 + lambda 条件判断 实现更复杂的生产者消费者模型。
✅ 八、总结
-
condition_variable是实现线程间通信的强大工具; -
核心思想是“谁该执行就放行,其他人都等待”;
-
在多线程编程中,控制逻辑 + 锁 + 唤醒机制 的配合至关重要。
更多推荐

所有评论(0)