【多线程】1116. 打印零与奇偶数
结合 这个题目,【多线程】---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);});
这里发生的事情是:
-
阻塞:如果谓词函数(
[&](){return (m_state == STATE_EVEN);}
)返回false
,则当前线程会被阻塞,并且与wait
方法关联的std::unique_lock<std::mutex>
(即lock
)会自动释放其持有的锁。这是为了确保其他线程可以获得锁并修改m_state
的值,从而可能使谓词函数在将来返回true
。 -
锁释放:当线程被阻塞时,
lock
关联的锁会被释放。这是std::condition_variable::wait
方法的一个重要特性,它允许其他线程在不被阻塞的情况下访问共享数据。 -
唤醒和重新获取锁:一旦其他线程修改了
m_state
的值,并且调用了cv.notify_one()
或cv.notify_all()
来唤醒等待的线程,被阻塞的线程会被唤醒,并尝试重新获取之前释放的锁。一旦锁被成功获取,线程会继续执行wait
方法之后的代码。 -
条件检查:在被唤醒并重新获取锁之后,
wait
方法会再次检查谓词函数。如果谓词函数仍然返回false
(这通常不应该发生,除非发生了虚假唤醒),线程会再次被阻塞并释放锁。这个过程会一直重复,直到谓词函数返回true
。
因此,
- 如果谓词函数返回
false
,则线程会被阻塞。 - 在线程被阻塞之前,
lock
关联的锁会被释放。