Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execution not switching between thread (c++11)

I am a beginner in C++11 multithreading. I am working with small codes and came into this problem. Here is the code:

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

std::mutex print_mutex;

void function1()
{
    std::cout << "Thread1 started" << std::endl;

    while (true)
    {
        std::unique_lock<std::mutex> lock(print_mutex);
        for (size_t i = 0; i<= 1000000000; i++)
            continue;
        std::cout << "This is function1" << std::endl;
        lock.unlock();
    }
}

void function2()
{
    std::cout << "Thread2 started" << std::endl;
    while (true)
    {
        std::unique_lock<std::mutex> lock(print_mutex);
        for (size_t i = 0; i <= 1000000000; i++)
            continue;
        std::cout << "This is function2" << std::endl;
        lock.unlock();
    }
}

int main()
{
    std::thread t1(function1);
    std::thread t2(function2);

    t1.join();
    t2.join();

    return 0;
}

I have written code with the intuition of expecting the following output:

Thread1 started
Thread2 started

This is function1
This is function2
This is function1
. .
.
.

But the output shown is as follows:

Thread1 started
Thread2 started

This is function1

This is function1
This is function1
.
.
.

Where am I going wrong?

like image 697
jeldikk Avatar asked Feb 11 '23 08:02

jeldikk


2 Answers

Unlocking a mutex does not guarantee that another thread that's waiting to lock the same mutex will immediately acquire a lock.

It only guarantees that the other thread will TRY to acquire the lock.

In this case, after you unlock the mutex in one thread, the same thread will immediately try to lock it again. Even though another thread was waiting patiently, for the mutex, it's not a guarantee that the other thread will win this time. The same thread that just locked it can succeed in immediately locking it again.

Today, you're seeing that the same thread always wins the locking race. Tomorrow, you may find that it's always the other thread that does. You have no guarantees, whatsoever, which thread will acquire the mutex when there's more than one thread going after the same mutex, at the same time. The winner depends on your CPU and other hardware architecture, how busy the system is loaded, at the time, and many other factors.

like image 82
Sam Varshavchik Avatar answered Feb 13 '23 02:02

Sam Varshavchik


Both of your thread is doing following steps:

  • Lock
  • Long empty loop
  • Print
  • Unlock
  • Lock
  • Long empty loop
  • (and so on)

Practically, you haven't left any time for context switching, there is a lock just right after the unlock. Solution: Swap the "lock" and the "long empty loop" steps, so only the "print" step will be locked, the scheduler can switch to the other thread during "long empty loop".

Welcome to threads!

Edit: Pro Tipp: Debugging multithreading programs is hard. But sometimes it's worth to insert a plain printf() to indicate locks and unlocks (the right order: lock, then printf and printf then unlock), even when the program seems correct. In this case you could see the zero gap between unlock-lock.

like image 42
ern0 Avatar answered Feb 13 '23 03:02

ern0