4

I am doing an application which handle multithreading for exercise.Let's suppose that we have 10 cars, and there is a parking which may contain at maximum 5 cars.If a car can't park it waits until there is a free room.
I am doing this with c++11 threads:

#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;
}

The problem is that there is no output, it seems like all threads are blocked waiting.

4

2 に答える 2

3

ここには 2 つの問題があります。

lockまず、オブジェクトを構築するとき

unique_lock<mutex> lock(cars_mux);

その後cars_muxロックされます。したがって、同じスレッドで再度ロックしようとするとエラー (未定義の動作) になります。これは、ループcars_mux内ですぐに実行しようとすることですwhile

cars_mux.lock();

while(true)第二に、ループを終了する方法がないため、スレッドが参加する方法がありませんtask。車は永遠に駐車し続けます! whileループはまったく必要ありません。

最初cars_mux.lock();の 、ループの最後にある対応するロック解除の試行while、およびwhileループ自体を削除すると、目的の動作が得られるはずです。

于 2012-07-05T22:50:51.660 に答える
2

Fraserの答えは素晴らしいですが、これを見たとき、実際の例がいいと思いました。

私はいくつかの変更を加えました:

  • 個人的には、忘れないように RAII を使用してロック/ロック解除するのが好きです (追加のスコープを意味する場合でも)。過去には、理解できない競合状態もありました.RAIIアプローチに切り替えると、それらも消えてしまうことがよくありました...簡単なので、やってください;)

  • 車がいつ出発するかを見るのが好きなので、そのための I/O も追加します。

記載されている問題の実際のコード例を次に示します。参考までに、libc ++でclang 3.1を使用しています。

#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の提案に従ってコードを簡略化。

于 2012-07-07T04:11:05.857 に答える