在多线程编程中,线程之间的同步与通信是非常经典的主题。
今天我们用一个小例子来演示:两个线程交替打印数字和字母,比如:

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 时,轮到字母线程。


⚙️ 二、核心思路

  1. 用一个全局互斥锁 mutex mtx 保证共享资源安全。

  2. 用一个条件变量 condition_variable cv 实现线程的等待与唤醒。

  3. 每个线程在自己的循环中判断:

    • 如果轮到自己,执行打印;

    • 否则调用 cv.wait() 挂起,等待另一个线程唤醒。

  4. 当打印结束后,修改 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 是实现线程间通信的强大工具;

  • 核心思想是“谁该执行就放行,其他人都等待”;

  • 在多线程编程中,控制逻辑 + 锁 + 唤醒机制 的配合至关重要。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐