查看: 40|回复: 0

力扣1116题:用C++实现多线程交替输出零、偶数、奇数

[复制链接]
  • TA的每日心情
    擦汗
    7 天前
  • 签到天数: 35 天

    [LV.5]常住居民I

    34

    主题

    0

    回帖

    65

    积分

    注册会员

    Rank: 2

    积分
    65
    发表于 2025-7-31 10:11:23 | 显示全部楼层 |阅读模式
    一、题目解读
    力扣1116题要求设计一个类,实现三个线程交替输出数字:一个线程输出连续的0,一个线程输出连续的偶数,另一个线程输出连续的奇数。输入参数n为总输出次数(每个线程各输出n次),输出需严格按照0-偶数-奇数的顺序循环,直至所有线程完成指定次数。题目核心在于多线程间的精确协作与同步控制。
    二、解题思路
    通过条件变量与互斥锁实现线程间的同步。关键在于设计状态变量next_type(标记下一个输出类型)与count(全局计数),结合cv.wait()的谓词条件判断线程唤醒时机。通过notify_all()确保所有等待线程重新检查条件,避免死锁或饥饿问题。
    三、步骤解析
    1. 初始化:构造函数中初始化n、count=1、zero_flag=true、next_type=0,确保首个输出为0。
    2. zero线程:循环n次,每次等待next_type=0,输出0后更新next_type为后续类型(奇数或偶数),并通知其他线程。
    3. even/odd线程:循环直至count > n或获取对应类型权限。通过谓词条件判断是否激活(如偶数线程等待next_type=2或结束条件),输出并更新状态,最后通知所有线程。
    4. 同步逻辑:利用unique_lock自动管理锁,条件变量结合谓词避免虚假唤醒,notify_all()保证所有线程重新评估条件。
    四、代码与注释
    1. class ZeroEvenOdd {
    2. private:
    3.     int n;          // 总输出次数
    4.     int count;      // 全局计数
    5.     bool zero_flag; // 初始标记
    6.     int next_type;  // 0: zero, 1: odd, 2: even
    7.     std::mutex mtx; // 互斥锁
    8.     std::condition_variable cv; // 条件变量

    9. public:
    10.     ZeroEvenOdd(int n) {
    11.         this->n = n;       // 初始化参数
    12.         count = 1;         // 从1开始计数
    13.         zero_flag = true;  // 首个线程为0
    14.         next_type = 0;     // 初始输出类型
    15.     }

    16.     void zero(function<void(int)> printNumber) {
    17.         for (int i = 0; i < n; ++i) {  // 循环n次
    18.             unique_lock<mutex> lock(mtx); // 加锁
    19.             cv.wait(lock, [this]{ return next_type == 0; }); // 等待类型为0
    20.             printNumber(0);              // 输出0
    21.             next_type = (count % 2 == 1)? 1 : 2; // 根据count奇偶决定后续类型
    22.             cv.notify_all();              // 唤醒所有线程
    23.         }
    24.     }

    25.     void even(function<void(int)> printNumber) {
    26.         while (true) {
    27.             unique_lock<mutex> lock(mtx);
    28.             cv.wait(lock, [this]{
    29.                 return next_type == 2 || count > n;  // 等待类型为2或结束条件
    30.             });
    31.             if (count > n) break;              // 结束循环
    32.             printNumber(count++);               // 输出偶数并递增计数
    33.             next_type = 0;                      // 重置类型
    34.             cv.notify_all();
    35.         }
    36.     }

    37.     void odd(function<void(int)> printNumber) {
    38.         while (true) {
    39.             unique_lock<mutex> lock(mtx);
    40.             cv.wait(lock, [this]{
    41.                 return next_type == 1 || count > n;  
    42.             });
    43.             if (count > n) break;
    44.             printNumber(count++);
    45.             next_type = 0;
    46.             cv.notify_all();
    47.         }
    48.     }
    49. };
    复制代码


    五、总结
    该解法巧妙利用条件变量与互斥锁实现线程间的精确协作,通过状态变量动态切换输出类型,避免复杂的条件判断。核心优势在于:
    1. 清晰的状态转移逻辑(next_type与count的协同);
    2. 谓词条件防止虚假唤醒,提升效率;
    3. notify_all()确保所有线程响应,避免饥饿问题。
    对多线程同步控制与力扣算法优化具有参考价值,适用于需要高并发协作的场景。
    来源:力扣题解




    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表