Search code examples
c++multithreadingmutexunique-lockconditional-variable

unique_lock.lock() causes abort in C++


I am learning C++ threads and i don't understand unique_lock mechanism very well. I reed This Link with Conditional variable, and more examples here but still I have my confusions:

1- So my question clearly is, doesn't unique_lock protect the mutual exclusion? I see in some examples when we use it on a shared mutex, the second thread cannot enter to that area which what I expect. But in this example as you see the output, all the threads can pass this line: std::unique_lockstd::mutex lck(mtx); is it just declaration or mutex gets locked as it declared?

2- why does the .lock() cause abort error? If I comment out that line all the threads starts in a row as you see in the screen shot output. I expect only thread0 pass the std::unique_lock<std::mutex> lck(mtx); it should be locked for other threads

enter image description here

Thanks

#include <mutex>
using namespace std;

condition_variable cv;
bool ready = false;
mutex mtx;
void print_id(int id) {

    // why all the threads can pass this line?
    std::unique_lock<std::mutex> lck(mtx);
    
   //i knew about the concept of two times locking, just thought there 
   //is something wrong with the constructor or i dont understand
    lck.lock(); // Having this line gives me abort.

    std::cout << "thread Starts: " << id << '\n';
    while (!ready) 
        cv.wait(lck);
    // ...
    std::cout << "thread Ends: " << id << '\n';
}

void go() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true;
    cv.notify_all();
}

void main()
{
    std::thread threads[5];
    // spawn 10 threads:
    for (int i = 0; i < 5; ++i)
    {
        this_thread::sleep_for(chrono::milliseconds(2000));
        threads[i] = std::thread(print_id, i);
    }

    std::cout << "10 threads ready to race...\n";
    go();                       // go!

    for (auto& th : threads) th.join();
}

Solution

  • std::unique_lock is an RAII type. When an object of that type is constructed, it locks the mutex that was passed to it, and upon destruction it unlocks the mutex, so you have scope level locking and unlocking.

    All that means is that when you do lck.lock(); you are trying to lock a mutex you have already locked by creating lck. std::unique_lock::lock() will throw an exception when you do this, and it is that uncaught exception that is causing abort() to be called.