2

I have one thread that needs to be blocked until something happens in another thread. It sounds very typical and I have this solution.

//thread 1
mux.lock();
//send work to another thread
mux.lock(); //will likely block which I want

//thread 2
//get the work sent over from thread 1
//work on it, then
mux.unlock(); //unblock thread 1 - all good

This works fine seemingly on Linux and it does not need a conditional var - except C++ standard says it is undefined behavior to acquire the lock in the same thread twice - which I do in thread 1.

Sclaker
  • 69
  • 4

3 Answers3

5

A standard std::mutex cannot be unlocked by a thread other than the one that locked it. It's undefined behavior to try.

From cppreference on std::mutex::unlock :

Unlocks the mutex.

The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.

For this reason your proposed strategy doesn't work with std::mutex.

Community
  • 1
  • 1
François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • Thx.I coded the condition variable solution and it 150% more code than the above one, but I can sleep better at night, :-) Basically, instead of a single mutex, I added one bool and one condition_variable in extra - put them into a single struct and allocate it once in heap ... you can imagine the rest of it. – Sclaker Nov 28 '19 at 00:12
0

Maybe try_lock? You can use spinlock. Sometrhing like:

while(mutex.try_lock()) 
    sleep(100);

will not crash and will block until first thread unlocks mutex. https://en.cppreference.com/w/cpp/thread/mutex/try_lock

bialy
  • 193
  • 2
  • 14
  • try_lock has the same above mentioned limitations as lock - even with spurious false return headache as I read – Sclaker Nov 27 '19 at 22:36
  • So if you want to stick to stdlib you can use recursive_mutex: [https://en.cppreference.com/w/cpp/thread/recursive_mutex][1] But it is still not perfect: `The maximum number of times that a recursive_mutex may be locked is unspecified, but after that number is reached, calls to lock will throw std::system_error and calls to try_lock will return false.` – bialy Nov 28 '19 at 06:32
0

The best/easiest solution I see is using boost::barrier; except it is not as flexible - for example you cannot add timeout behavior which is typically needed.

Sclaker
  • 69
  • 4