4

我正在做一个处理多线程运动的应用程序。假设我们有 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;
}

问题是没有输出,似乎所有线程都被阻塞等待。

4

2 回答 2

3

这里有2个问题:

首先,当你构造你的lock对象时

unique_lock<mutex> lock(cars_mux);

然后cars_mux被锁定。因此,尝试在同一个线程中再次锁定是一个错误(未定义的行为cars_mux) ,这是您尝试在while循环内立即执行的操作

cars_mux.lock();

Secondly, there is no way for the threads to join since there is no way to exit the while(true) loop in task - cars will continue to park forever! You don't need the while loop at all.

If you remove the first cars_mux.lock();, the corresponding unlock attempt at the end of the while loop, and the while loop itself, you should get the desired behaviour.

于 2012-07-05T22:50:51.660 回答
2

Fraser's answer is great, but when I looked at this I felt a working example would be nice.

I made some changes:

  • Personally, I like to use RAII to lock/unlock so that you don't forget to do so (even if it means extra scopes). In the past, I've also had race conditions that I couldn't figure out, and switching to the RAII approach has often made those disappear as well... It's just easier, so do it ;)

  • I like to see when the cars leave, so I add I/O for that too.

Here's the working code example for the stated problem. FYI, I use clang 3.1 with 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;
}

Edit: Simplified code as per Rami Al Zuhouri's suggestion.

于 2012-07-07T04:11:05.857 回答