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

一、题目解读

力扣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()保证所有线程重新评估条件。

四、代码与注释

cpp 复制代码
class ZeroEvenOdd {
private:
    int n;          // 总输出次数
    int count;      // 全局计数
    bool zero_flag; // 初始标记
    int next_type;  // 0: zero, 1: odd, 2: even
    std::mutex mtx; // 互斥锁
    std::condition_variable cv; // 条件变量

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

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

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

    void odd(function<void(int)> printNumber) {
        while (true) {
            unique_lock<mutex> lock(mtx);
            cv.wait(lock, [this]{ 
                return next_type == 1 || count > n;  
            });
            if (count > n) break;
            printNumber(count++);
            next_type = 0;
            cv.notify_all();
        }
    }
};

五、总结

该解法巧妙利用条件变量与互斥锁实现线程间的精确协作,通过状态变量动态切换输出类型,避免复杂的条件判断。核心优势在于:

  1. 清晰的状态转移逻辑(next_type与count的协同);

  2. 谓词条件防止虚假唤醒,提升效率;

  3. notify_all()确保所有线程响应,避免饥饿问题。

对多线程同步控制与力扣算法优化具有参考价值,适用于需要高并发协作的场景。

来源:力扣题解

相关推荐
凡人叶枫21 分钟前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
会叫的恐龙31 分钟前
C++ 核心知识点汇总(第六日)(字符串)
c++·算法·字符串
小糯米60142 分钟前
C++顺序表和vector
开发语言·c++·算法
独望漫天星辰1 小时前
C++ 多态深度解析:从语法规则到底层实现(附实战验证代码)
开发语言·c++
We་ct1 小时前
LeetCode 56. 合并区间:区间重叠问题的核心解法与代码解析
前端·算法·leetcode·typescript
王老师青少年编程2 小时前
2024年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第3题)
c++·题解·真题·csp·信奥赛·csp-s·提高组
凡人叶枫2 小时前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
CSDN_RTKLIB2 小时前
使用三方库头文件未使用导出符号情景
c++
rainbow68893 小时前
Linux文件描述符与重定向原理
c++
努力学算法的蒟蒻4 小时前
day79(2.7)——leetcode面试经典150
算法·leetcode·职场和发展