I have a multi threaded C++ program which simulates a car workshop. Basically a car
is a thread here and a station
is a resource. It works like this: Car enters a workshop and it has a list of stations (just ints), that it has to visit, to get repaired. There are 3 types of stations:
The last two types would be easy for me, cuz in the 1x1
type I just lock the mutex on station
and other threads have to wait. On the 2x1
type I just go for std::lock
on two stations to avoid deadlock etc.
The problem is with the first type. Lets imagine that repairing two cars at once means that one car is on the left hand side of the station and the other one on the right hand side (I will have to draw this situation with ncurses
as well). So I thought about implementing a station for 1x2
type like this:
class station1x2 {
public:
std::mutex r_mutex;
std::mutex l_mutex;
}
So I would like to lock either the r_mutex
or the l_mutex
, so there are 4 possible scenarios:
The problem here is: Is there in C++ a mechanism to lock just one of given mutexes? (like I give some function my r_mutex and l_mutex and it chooses the not locked one and locks it for me).
A mutex is not the correct synchronisation primitive here. This could be done with a semaphore (basically a 0-n primitive where a mutex is 0-1), but there is no semaphore in the standard library.
There is a condition variable, however, which you can use here. You will need:
When entering the station, lock the mutex and see if there's any free space. If there is, occupy one, release the mutex, and get repairs. If both are full, wait on the condition variable (this will release the mutex).
When done with repairs, lock the mutex, mark your space as free, release the mutex and notify the condition variable (since there's free space now).
In code:
class station1x2 {
public:
std::mutex mutex;
std::condition_variable cond;
int freeSpaces;
void enter() {
std::unique_lock<std::mutex> l(mutex);
cond.wait(l, [&]() { return freeSpaces > 0; }
--freeSpaces;
}
void exit() {
{
std::unique_lock<std::mutex> l(mutex);
++freeSpaces;
}
cond.notify_one();
}
}
In your case, I would use the try_lock
method. This method returns true
(and locks the mutex) if the lock is possible, false
otherwise (already locked mutex).
if (!r_mutex.try_lock() && !l_mutex.try_lock())
std::cout << "All mutexes already locked" << std::endl;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With