Multithreading application has no way out

I am making an application that handles multithreading for exercises. Suppose we have 10 cars, and there is a parking lot that can contain a maximum of 5 cars. If the car cannot park, it waits until a free room appears.
I do this with C ++ 11 streams:

#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 way out, it seems that all threads are blocked waiting.

+4
source share
2 answers

There are 2 questions here:

First, when you create a lock object

 unique_lock<mutex> lock(cars_mux); 

then cars_mux blocked. Thus, it is an error ( undefined behavior ) to try to block cars_mux again in the same thread that you are trying to do right away inside the while loop on

 cars_mux.lock(); 

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

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

+3
source

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

I made some changes:

  • Personally, I like to use RAII to lock / unlock so you don't forget to do it (even if it means extra areas). Previously, I also had race conditions that I could not understand, and switching to the RAII approach often made them disappear ... It's just easier, so do it;)

  • I like to see when cars go out, so I also add I / O.

Here is an example of working code for the indicated problem. FYI, I am using 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 proposed by Rami Al Zuhuri.

+2
source

All Articles