我正在做一个处理多线程练习的应用程序。我们假设我们有10辆车,并且有一个停车场,最多可以包含5辆车。如果一辆车无法停车,它会等到有空房间。
我用c ++ 11线程做这个:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
int cars=0;
int max_cars=5;
mutex cars_mux;
condition_variable cars_cond;
bool pred()
{
return cars< max_cars;
}
void task()
{
unique_lock<mutex> lock(cars_mux);
while(true)
{
cars_mux.lock();
cars_cond.wait(lock,pred);
cars++;
cout << this_thread::get_id() << " has parked" << endl;
cars_mux.unlock();
this_thread::sleep_for(chrono::seconds(1)); // the cars is parked and waits some time before going away
cars_mux.lock();
cars--;
cars_cond.notify_one();
cars_mux.unlock();
}
}
int main(int argc, char** argv)
{
thread t[10];
for(int i=0; i<10; i++)
t[i]=thread(task);
for(int i=0; i<10; i++)
t[i].join();
return 0;
}
问题在于没有输出,似乎所有线程都被阻塞等待。
答案 0 :(得分:3)
这里有两个问题:
首先,构建lock
对象
unique_lock<mutex> lock(cars_mux);
然后cars_mux
被锁定。因此,尝试在同一个线程中再次锁定cars_mux
是一个错误(undefined behaviour),这是您尝试在while
循环中立即执行的操作
cars_mux.lock();
其次,线程无法加入,因为无法退出while(true)
中的task
循环 - 汽车将继续永久停放!您根本不需要while
循环。
如果删除第一个cars_mux.lock();
,while
循环结束时的相应解锁尝试以及while
循环本身,则应该获得所需的行为。
答案 1 :(得分:2)
弗雷泽的答案很棒,但当我看到这个时,我觉得一个有效的例子会很好。
我做了一些改变:
就个人而言,我喜欢使用RAII来锁定/解锁,这样你就不会忘记这样做(即使它意味着额外的范围)。在过去,我也遇到了一些我无法弄清楚的竞争条件,而转换到RAII方法往往也会让它们消失......它更容易,所以这样做;)
我喜欢看车何时离开,所以我也为此添加了I / O.
这是所述问题的工作代码示例。仅供参考,我使用clang 3.1和libc ++:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
using namespace std;
int cars=0;
int max_cars=5;
mutex cars_mux;
condition_variable cars_cond;
bool pred()
{
return cars < max_cars;
}
void task()
{
{
unique_lock<mutex> carlock(cars_mux);
cars_cond.wait(carlock,pred);
cars++;
cout << "Thread " << this_thread::get_id()
<< " has parked. There are " << cars << " parked cars." << endl;
}
this_thread::sleep_for(chrono::seconds(1));
{
unique_lock<mutex> carlock(cars_mux);
cars--;
cout << "Thread " << this_thread::get_id()
<< " has left. There are " << cars << " parked cars." << endl;
cars_cond.notify_one();
}
}
int main(int argc, char** argv)
{
const int NumThreads = 10;
thread t[NumThreads];
for(int i=0; i<NumThreads; i++)
t[i]=thread(task);
for(int i=0; i<NumThreads; i++)
t[i].join();
return 0;
}
编辑:根据Rami Al Zuhouri的建议简化代码。