Why does unlocking a unique_lock cause my program to crash? - c++

I am running into some odd behavior regarding unique_lock. After creating it, I try to call unlock, but it crashes my program. I have created a minimal example that consistently crashes on the unlock function (used gdb to confirm).
#include <iostream>
#include <string>
#include <mutex>
#include <thread>
#include <chrono>
std::mutex myMutex;
void lockMe()
{
std::unique_lock lock(myMutex);
std::cout << "Thread\n";
}
int main()
{
std::unique_lock lock(myMutex);
auto c = std::thread(lockMe);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Main\n";
myMutex.unlock();
c.join();
return 0;
}
Can anyone explain why this is happening?

By creating std::unique_lock lock(myMutex); you are granting mutex lock / unlock control to the lock object. if you manually unlock the mutex while it is still under control of the lock object you will violate that constraint and lock destructor will perform a double unlock attempt.
It is similar to all the RAII wrappers - once you grant resource control to RAII object you should not interfere with it by manually disposing of the resource.
Note that std::unique_lock offers a method to unlock the locked mutex prior to scope end that won't cause problems:
lock.unlock();

Related

std::condition_variable::notify_all() - I need an example

I need an example of using notify_all() method. Because I cannot understand how should it work.
Every waiting thread begins with code like that:
std::unique_lock<std::mutex> lock(mutex);
condition_variable.wait(lock, [](){return SOMETHING;});
At the very beginning, waiting thread needs to acquire a mutex. So if there are more than one waiting thread, rest of them will wait to lock a mutex. So what is the purpose of using notify_all() if waiting threads stuck at locking mutex and do not execute a method wait() at all? These threads will wake up one by one instead of simultaneously.
The mutex guards the internal state of the condition_variable. Calling wait on the condition_variable causes the mutex to be unlocked. So while waiting, threads do not own the mutex.
When the wait completes, the mutex is again (atomically) acquired before the call to wait returns.
The threads are not contending on the mutex, they are contending on the condition itself.
You are free to unlock the lock as soon as you return from wait if you wish. If you want to allow multiple threads to synchronise on a condition, for example, this is how you would do it. You can also use this feature to implement a semaphore.
example:
This code processes things in batches of 10. Note that notify_all() goes after the unlock():
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <vector>
void emit(std::string const& s)
{
static std::mutex m;
auto lock = std::unique_lock<std::mutex>(m);
std::cout << s << std::endl;
}
std::mutex m;
std::condition_variable cv;
int running_count = 0;
void do_something(int i)
{
using namespace std::literals;
auto lock = std::unique_lock<std::mutex>(m);
// mutex is now locked
cv.wait(lock, // until the cv is notified, the mutex is unlocked
[]
{
// mutex has been locked here
return running_count < 10;
// if this returns false, mutex will be unlocked again, but code waits inside wait() for a notify()
});
// mutex is locked here
++running_count;
lock.unlock();
// we are doing work after unlocking the mutex so others can also
// work when notified
emit("running " + std::to_string(i));
std::this_thread::sleep_for(500ms);
// manipulating the condition, we must lock
lock.lock();
--running_count;
lock.unlock();
// notify once we have unlocked - this is important to avoid a pessimisation.
cv.notify_all();
}
int main()
{
std::vector<std::thread> ts;
for (int i = 0 ; i < 200 ; ++i)
{
ts.emplace_back([i] { do_something(i); });
}
for (auto& t : ts) {
if (t.joinable()) t.join();
}
}

what are the use cases for std::unique_lock::release?

In what situations would one use the release method of std::unique_lock ?
I made the mistake of using the release method instead of the unlock method and it took a while to understand why the following code wasn't working.
#include <mutex>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
std::mutex mtx;
void foo()
{
std::unique_lock<std::mutex> lock(mtx);
std::cout << "in critical section\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
lock.release();
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i)
threads.push_back(std::thread(foo));
for (std::thread& t : threads)
t.join();
}
There's a good use for it in this answer where ownership of the locked state is explicitly transferred from a function-local unique_lock to an external entity (a by-reference Lockable parameter).
This concrete example is typical of the use: To transfer ownership of the locked state from one object (or even type) to another.
.release() is useful when you want to keep the mutex locked until some other object/code decides to unlock it... for example, if you were calling into a function that needed the mutex locked and would unlock it itself at a certain point in that function's processing, where that function accepts only a std::mutex& rather than a std::unique_lock<std::mutex>&&. (Conceptually similar to the uses for smart pointer release functions.)

Mutexes inside if condition

I have a problem with mutexes...
This is the general structure of my code:
#include <mutex>
std::mutex m;
While(1){
m.lock();
if(global_variable1==1){
//CODE GOES HERE
if (err==error::eof){
cout<<"error!"<<endl;
//should I put a m.unlock() here??
continue;
}
int something=1;
global_variable2=something;
}
m.unlock();
usleep(100000);
}
Basically, I want to change global variable safely, so I think I need to use mutexes. I should only unlock the mutex after that "if(global_variable1==1)" function, but if there is an error, the mutex won't be unlocked.. Can I unlock it before the "continue"? Or is this going mess up with anything else? Can having two unlocks for the same mutex.lock() have a undesired behaviour?
This is why C++ has separate lock and mutex classes: a lock is a handy RAII class that will make sure that your mutex gets unlocked even when exceptions are thrown or some other idiot programmer adds a new return/break/continue into the program. Here's how this program works with std::unique_lock:
#include <mutex>
std::mutex m;
While(1){
std::unique_lock<std::mutex> lock(m);
if(global_variable1==1){
//CODE GOES HERE
if (err==error::eof){
cout<<"error!"<<endl;
continue;
}
int something=1;
global_variable2=something;
}
lock.unlock();
usleep(100000);
}
Do not lock/unlock mutexes manually! Instead use a guard, e.g., std::lock_guard<std::mutex>: the guard will acquire a lock upon construction an release it upon destruction. To limit the time the lock is held, just use a block:
while (true) {
{
std::lock_guard<std::mutex> cerberos(m);
// ...
}
sleep(n);
}

unique_lock across threads?

I am having some trouble conceptualizing how unique_lock is supposed to operate across threads. I tried to make a quick example to recreate something that I would normally use a condition_variable for.
#include <mutex>
#include <thread>
using namespace std;
mutex m;
unique_lock<mutex>* mLock;
void funcA()
{
//thread 2
mLock->lock();//blocks until unlock?Access violation reading location 0x0000000000000000.
}
int _tmain(int argc, _TCHAR* argv[])
{
//thread 1
mLock = new unique_lock<mutex>(m);
mLock->release();//Allows .lock() to be taken by a different thread?
auto a = std::thread(funcA);
std::chrono::milliseconds dura(1000);//make sure thread is running
std::this_thread::sleep_for(dura);
mLock->unlock();//Unlocks thread 2's lock?
a.join();
return 0;
}
unique_lock should not be accessed from multiple threads at once. It was not designed to be thread-safe in that manner. Instead, multiple unique_locks (local variables) reference the same global mutex. Only the mutex itself is designed to be accessed by multiple threads at once. And even then, my statement excludes ~mutex().
For example, one knows that mutex::lock() can be accessed by multiple threads because its specification includes the following:
Synchronization: Prior unlock() operations on the same object shall synchronize with (4.7) this operation.
where synchronize with is a term of art defined in 4.7 [intro.multithread] (and its subclauses).
That doesn't look at all right. First, release is "disassociates the mutex without unlocking it", which is highly unlikely that it is what you want to do in that place. It basically means that you no longer have a mutex in your unique_lock<mutex> - which will make it pretty useless - and probably the reason you get "access violation".
Edit: After some "massaging" of your code, and convincing g++ 4.6.3 to do what I wanted (hence the #define _GLIBCXX_USE_NANOSLEEP), here's a working example:
#define _GLIBCXX_USE_NANOSLEEP
#include <chrono>
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;
mutex m;
void funcA()
{
cout << "FuncA Before lock" << endl;
unique_lock<mutex> mLock(m);
//thread 2
cout << "FuncA After lock" << endl;
std::chrono::milliseconds dura(500);//make sure thread is running
std::this_thread::sleep_for(dura); //this_thread::sleep_for(dura);
cout << "FuncA After sleep" << endl;
}
int main(int argc, char* argv[])
{
cout << "Main before lock" << endl;
unique_lock<mutex> mLock(m);
auto a = std::thread(funcA);
std::chrono::milliseconds dura(1000);//make sure thread is running
std::this_thread::sleep_for(dura); //this_thread::sleep_for(dura);
mLock.unlock();//Unlocks thread 2's lock?
cout << "Main After unlock" << endl;
a.join();
cout << "Main after a.join" << endl;
return 0;
}
Not sure why you need to use new to create the lock tho'. Surely unique_lock<mutex> mlock(m); should do the trick (and corresponding changes of mLock-> into mLock. of course).
A lock is just an automatic guard that operates a mutex in a safe and sane fashion.
What you really want is this code:
std::mutex m;
void f()
{
std::lock_guard<std::mutex> lock(m);
// ...
}
This effectively "synchronizes" calls to f, since every thread that enters it blocks until it manages to obtain the mutex.
A unique_lock is just a beefed-up version of the lock_guard: It can be constructed unlocked, moved around (thanks, #MikeVine) and it is itself a "lockable object", like the mutex itself, and so it can be used for example in the variadic std::lock(...) to lock multiple things at once in a deadlock-free way, and it can be managed by an std::condition_variable (thanks, #syam).
But unless you have a good reason to use a unique_lock, prefer to use a lock_guard. And once you need to upgrade to a unique_lock, you'll know why.
As a side-note, the above answers skip over the difference between immediate and deferred locking of mutex:
#include<mutex>
::std::mutex(mu);
auto MyFunction()->void
{
std::unique_lock<mutex> lock(mu); //Created instance and immediately locked the mutex
//Do stuff....
}
auto MyOtherFunction()->void
{
std::unique_lock<mutex> lock(mu,std::defer_lock); //Create but not locked the mutex
lock.lock(); //Lock mutex
//Do stuff....
lock.unlock(); //Unlock mutex
}
MyFunction() shows the widely used immediate lock, whilst MyOtherFunction() shows the deferred lock.

Behavior of condition_variable_any when used with a recursive_mutex?

When using condition_variable_any with a recursive_mutex, will the recursive_mutex be generally acquirable from other threads while condition_variable_any::wait is waiting? I'm interested in both Boost and C++11 implementations.
This is the use case I'm mainly concerned about:
void bar();
boost::recursive_mutex mutex;
boost::condition_variable_any condvar;
void foo()
{
boost::lock_guard<boost::recursive_mutex> lock(mutex);
// Ownership level is now one
bar();
}
void bar()
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
// Ownership level is now two
condvar.wait(lock);
// Does this fully release the recursive mutex,
// so that other threads may acquire it while we're waiting?
// Will the recursive_mutex ownership level
// be restored to two after waiting?
}
By a strict interpretation of the Boost documentation, I concluded that condition_variable_any::wait will not generally result in the recursive_mutex being acquirable by other threads while waiting for notification.
Class condition_variable_any
template<typename lock_type> void wait(lock_type& lock)
Effects:
Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or
this->notify_all(), or spuriously. When the thread is unblocked (for
whatever reason), the lock is reacquired by invoking lock.lock()
before the call to wait returns. The lock is also reacquired by
invoking lock.lock() if the function exits with an exception.
So condvar.wait(lock) will call lock.unlock, which in turn calls mutex.unlock, which decreases the ownership level by one (and not necessarily down to zero).
I've written a test program that confirms my above conclusion (for both Boost and C++11):
#include <iostream>
#define USE_BOOST 1
#if USE_BOOST
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/recursive_mutex.hpp>
namespace lib = boost;
#else
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
namespace lib = std;
#endif
void bar();
lib::recursive_mutex mutex;
lib::condition_variable_any condvar;
int value = 0;
void foo()
{
std::cout << "foo()\n";
lib::lock_guard<lib::recursive_mutex> lock(mutex);
// Ownership level is now one
bar();
}
void bar()
{
std::cout << "bar()\n";
lib::unique_lock<lib::recursive_mutex> lock(mutex);
// Ownership level is now two
condvar.wait(lock); // Does this fully release the recursive mutex?
std::cout << "value = " << value << "\n";
}
void notifier()
{
std::cout << "notifier()\n";
lib::this_thread::sleep_for(lib::chrono::seconds(3));
std::cout << "after sleep\n";
// --- Program deadlocks here ---
lib::lock_guard<lib::recursive_mutex> lock(mutex);
value = 42;
std::cout << "before notify_one\n";
condvar.notify_one();
}
int main()
{
lib::thread t1(&foo); // This results in deadlock
// lib::thread t1(&bar); // This doesn't result in deadlock
lib::thread t2(&notifier);
t1.join();
t2.join();
}
I hope this helps anyone else facing the same dilemma when mixing condition_variable_any and recursive_mutex.
You can fix this design by adding a parameter allowed_unlock_count to every function which operates on the mutex object; there are two types of guarantees that can be made about allowed_unlock_count:
(permit-unlock-depth) allowed_unlock_count represents the depth of permitted unlocking of mutex: the caller allows bar to unlock the mutex allowed_unlock_count times. After such unlocking, no guarantee is made about the state of mutex.
(promise-unlock) allowed_unlock_count represents the depth of locking of mutex: the caller guarantees that unlocking mutex exactly allowed_unlock_count times will allow other threads to grab the mutex object.
These guarantees are pre- and post-conditions of functions.
Here bar depends on (promise-unlock):
// pre: mutex locking depth is allowed_unlock_count
void bar(int allowed_unlock_count)
{
// mutex locking depth is allowed_unlock_count
boost::unique_lock<boost::recursive_mutex> lock(mutex);
// mutex locking depth is allowed_unlock_count+1
// you might want to turn theses loops
// into an a special lock object!
for (int i=0; i<allowed_unlock_count; ++i)
mutex.unlock();
// mutex locking depth is 1
condvar.wait(lock); // other threads can grab mutex
// mutex locking depth is 1
for (int i=0; i<allowed_unlock_count; ++i)
mutex.lock();
// mutex locking depth is allowed_unlock_count+1
}
// post: mutex locking depth is allowed_unlock_count
Called function must explicitly allowed to decrease locking depth by the caller.