Search code examples
c++c++11concurrencylocking

Can you access a single std::unique_lock from multiple 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;
}

Solution

  • 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).