【多线程】1116. 打印零与奇偶数

 

1116. 打印零与奇偶数 - 力扣(LeetCode)

 

结合  这个题目,【多线程】---1115. 交替打印 FooBar - He_LiangLiang - 博客园 ,来理解 条件变量  condition_variable 的用法。

以及  cv.wait(lock, [&](){  some contition; });  这里 wait 的用法;

wait 的时候,锁被释放了,程序阻塞了。

 

思路
参考了其他人的题解来解答的。、
1.在 zero, even, odd 里面写for循环来打印(最初不明白这点,参考了题解之后才明白)
解题过程
2.定义状态枚举类型(当时 奇偶状态定义反了,导致了死锁)
3.如果用notify_one, 会有死锁; 必须用 notify_all
复杂度
  • 时间复杂度: O(∗)O(*)O()
  • 空间复杂度: O(∗)O(*)O()
class ZeroEvenOdd {
private:
    typedef enum STATE{
        STATE_0 = 0,
        STATE_ODD, // 奇数
        STATE_0_0,
        STATE_EVEN, // 偶数
    }THREAD_STATE;
    int n;
    std::mutex  mtx;
    condition_variable cv;
    THREAD_STATE m_state=STATE_0;
    std::atomic<int> m_number {0};
public:
    ZeroEvenOdd(int n) {
        this->n = n;
    }

    // printNumber(x) outputs "x", where x is an integer.
    void zero(function<void(int)> printNumber) {        
        for(int i=1; i<=n; ++i){
            unique_lock<mutex> lock(mtx);
            cv.wait(lock, [&](){return (m_state == STATE_0 || m_state == STATE_0_0);});        
            //printf("zero i:%d\n", 0);
            printNumber(0);
            if(m_state == STATE_0){
                m_state = STATE_ODD;
            }
            if(m_state == STATE_0_0){
                m_state = STATE_EVEN;
            }
            cv.notify_all();
        }
    }

    // 偶数
    void even(function<void(int)> printNumber) {
        for(int i=2; i<=n; i+=2){
            unique_lock<mutex> lock(mtx);
            cv.wait(lock, [&](){return (m_state == STATE_EVEN);});              
           // printf("even i:%d\n", i);
            m_state = STATE_0;
            printNumber(i);
            cv.notify_all();
        }
    }

    // 奇数
    void odd(function<void(int)> printNumber) {
        for(int i=1; i<=n; i+=2){            
            unique_lock<mutex> lock(mtx);
            cv.wait(lock, [&](){return (m_state == STATE_ODD);});       
            //printf("odd i:%d\n", i);       
            m_state = STATE_0_0;
            printNumber(i);
            cv.notify_all();
        }
    }
};

作者:Henry
链接:https://leetcode.cn/problems/print-zero-even-odd/solutions/2984763/duo-xian-cheng-1116-da-yin-ling-yu-qi-ou-69d8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

在C++的多线程编程中,std::condition_variable 的 wait 方法用于阻塞当前线程,直到某个条件被满足(即提供的谓词函数返回 true)或者发生虚假唤醒(spurious wakeup)。这个方法接受两个参数:一个 std::unique_lock<std::mutex> 对象和一个谓词函数(通常是一个 lambda 表达式或函数对象)。

对于你的代码片段:

cv.wait(lock, [&](){return (m_state == STATE_EVEN);});

 

这里发生的事情是:

  1. 阻塞:如果谓词函数([&](){return (m_state == STATE_EVEN);})返回 false,则当前线程会被阻塞,并且与 wait 方法关联的 std::unique_lock<std::mutex>(即 lock)会自动释放其持有的锁。这是为了确保其他线程可以获得锁并修改 m_state 的值,从而可能使谓词函数在将来返回 true

  2. 锁释放:当线程被阻塞时,lock 关联的锁会被释放。这是 std::condition_variable::wait 方法的一个重要特性,它允许其他线程在不被阻塞的情况下访问共享数据。

  3. 唤醒和重新获取锁:一旦其他线程修改了 m_state 的值,并且调用了 cv.notify_one() 或 cv.notify_all() 来唤醒等待的线程,被阻塞的线程会被唤醒,并尝试重新获取之前释放的锁。一旦锁被成功获取,线程会继续执行 wait 方法之后的代码。

  4. 条件检查:在被唤醒并重新获取锁之后,wait 方法会再次检查谓词函数。如果谓词函数仍然返回 false(这通常不应该发生,除非发生了虚假唤醒),线程会再次被阻塞并释放锁。这个过程会一直重复,直到谓词函数返回 true

因此,

  • 如果谓词函数返回 false,则线程会被阻塞。
  • 在线程被阻塞之前,lock 关联的锁会被释放。
posted @ 2024-11-11 14:58  He_LiangLiang  阅读(6)  评论(0编辑  收藏  举报