bparikh
bparikh

Reputation: 63

Learning about mutexes and threads - Question regarding race conditions

I'm teaching myself a bit about concurrent programming, specifically using mutexes and threads in C++. I've written the following small example:

#include <iostream>
#include <thread>
#include <mutex>
// #include <chrono>

std::mutex M1,M2;

void task_one () {
    std::cout << "AAAA!\n";
    M1.lock();
    // std::cout << "M1 locked in A\n";
    M2.lock();
    // std::cout << "M2 locked in A\n";
    std::cout << "BBBB!\n";
    M2.unlock();
    // std::cout << "M2 unlocked in A\n";
    M1.unlock();
    // std::cout << "M2 unlocked in A\n";
}

void task_two () {
    std::cout << "CCCC!\n";
    M2.lock();
    // std::cout << "M2 locked in B\n";
    M1.lock();
    // std::cout << "M1 locked in B\n";
    std::cout << "DDDD!\n";
    // M1.unlock();
    // std::cout << "M1 unlocked in B\n";
    M2.unlock();
    // std::cout << "M2 unlocked in B\n";
}

int main () {
    std::thread th1 (task_one);
    std::thread th2 (task_two);
    th1.join();
    th2.join();

    // th1.detach();
    // th2.detach();
    // std::chrono::milliseconds timespan(10);
    // std::this_thread::sleep_for(timespan);
    return 0;
}

I expected this code to print

AAAA!
CCCC!

and then deadlock when task_one attempts to acquire the lock on M2 (because task_two will have already acquired that lock). However, it prints

AAAA!
BBBB!
CCCC!
DDDD!

Why isn't there a deadlock? In addition, is this an example of a race condition, or is this code thread-safe? I think that there is a race condition because if task_one can acquire a lock on M2 before task_two can, then everything will execute (that is, task_one will finish and then allow task_two to begin). However, I ran this quite a few times with the same results. Also, if my verbiage as it relates to locks and threads is incorrect, please correct me.

Upvotes: 0

Views: 29

Answers (1)

catnip
catnip

Reputation: 25388

Just because a deadlock can happen (as indeed it can in the code as posted), doesn't mean it always will happen.

In your case, task_one happens to run to completion before task_two gets going at all.

Multi-threading is like that: slippery.

Upvotes: 2

Related Questions