#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
std::mutex globalMutex;
std::condition_variable globalCondition;
int global = 0;
int activity = 0;
int CountOfThread = 1; // or more than 1
// just for console display, not effect the problem
std::mutex consoleMutex;
void producer() {
while (true) {
{
std::unique_lock<std::mutex> lock(globalMutex);
while (activity == 0) {
lock.unlock();
std::this_thread::yield();
lock.lock();
}
global++;
globalCondition.notify_one();
}
std::this_thread::yield();
}
}
void customer() {
while (true) {
int x;
{
std::unique_lock<std::mutex> lock(globalMutex);
activity++;
globalCondition.wait(lock); // <- problem
activity--;
x = global;
}
{
std::lock_guard<std::mutex> lock(consoleMutex);
std::cout << x << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int _tmain(int argc, _TCHAR* argv[])
{
for (int i = 0; i < CountOfThread; ++i) {
std::thread(customer).detach();
}
std::thread(producer).detach();
getchar();
return 0;
}
我想要的是确保每次有一个客户线程来增加全局,期望显示如:1,2,3 ......,但我看到的是全球价值将在等待和活动 - 因此,实际显示是:1,23,56,78 ...... ....
我发现问题出现在wait()中,在wait(),'解锁,等待,锁定',发信号(等待返回)和mutex.lock之间有3个步骤,它不是原子操作,生产者线程可能会在wait()锁定互斥锁之前锁定互斥锁,并且活动仍然不为零,所以全局会意外地增加
有没有办法确定我的期望?
答案 0 :(得分:1)
问题在于activity
是&gt; 0,producer
可循环抓取锁,递增全局,并通知条件变量。 (通知不必有相应的服务员)。
你反复拨打thread.yield
是一个红旗 - 他们的意思是你在投票,而不是等待。我认为解决方案是您需要两个条件变量。生产者等待一个直到被消费者通知,消费者等待另一个直到生产者通知。我不太确定你如何与多个消费者合作。
答案 1 :(得分:0)
我发现在线程的上下文中它有助于我。例如,如果您是客户,您等待什么?通过你,我的意思是在线程的上下文。当您这样想时,使用monitors进行编码非常简单。
现在,正如马丁所说,我相信重复调用thread.yield
有点可怕。这可能导致代码的可怕交错。
为了展示代码无法工作的示例,让我们快速进行交错:
activity
。然后,由于调用wait
,该线程进入休眠状态。 wait
之后,另一个线程被唤醒。这是因为wait
解锁了传递给它的互斥锁。 globalMutex
并增加activity
。然后它等了。CountOfThread
个线程数,因为多线程代码完全可以实现。 activity == 0
并解锁。但是,它没有notify_one
(即信号)。然后它产生。这可能会导致代码不明确和混乱。 我的建议:
yield
。这可能导致复杂且难以阅读的无效监视器代码。 在您的情况下,解决方案并不像您想象的那么复杂。使用我的原始建议:在线程的上下文中思考。例如,当生产者线程正在运行时,它希望在客户没有注意到global
已被更改时等待。当客户线程正在运行时,只要生产者未更改global
,它就会等待。
以下是您想要的行为示例:
mutex m;
condition_variable cv;
int global = 0, prev_global = 0;
void producer()
{
while (true)
{
unique_lock<mutex> lock(m);
while (prev_global != global)
{
cv.wait(lock);
}
prev_global = global++;
cv.notify_one();
lock.unlock();
}
}
void customer()
{
while (true)
{
unique_lock<mutex> lock(m);
while (prev_global == global)
{
cv.wait(lock);
}
prev_global = global;
cv.notify_one();
lock.unlock();
}
}
int main()
{
vector<thread> pool;
for (int i = 0; i < 5; ++i)
{
pool.push_back(thread (customer));
}
pool.push_back(thread (producer));
for (auto it = pool.begin(); it != pool.end(); ++it)
{
it->join();
}
return 0;
}