Home > Net >  Mutex does not work as I expect. What is my mistake?
Mutex does not work as I expect. What is my mistake?

Time:04-22

I was trying to figure out the data race theme, and I made this code. Here we work with the shared element wnd. I thought that by putting lock in the while loop, I would prohibit the th1 thread from working with wnd, but this did not happen and I see an unobstructed output of the th1 thread.

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

int main()
{
     bool wnd = true;
     std::mutex mutex;
     std::unique_lock<std::mutex> lock(mutex, std::defer_lock);


     std::thread th1([&]() {
         int i = 0;
         while (true)
         {
             
               i;
             lock.lock();
             if (wnd)
                 std::cout << i << "   WND TRUE" << std::endl;
             else
                 std::cout << i << "   WND FALSE" << std::endl;
             lock.unlock();
             std::this_thread::sleep_for(std::chrono::milliseconds(100));
         }
     });

     
     while (true)
     {
        lock.lock();
         std::this_thread::sleep_for(std::chrono::milliseconds(2000));
         if (wnd)
             wnd = false;
         else
             wnd = true;
        lock.unlock();

         std::this_thread::sleep_for(std::chrono::milliseconds(100));
     }
     
     th1.join();
     return 0;
}

To tell the truth, I was hoping to see that the th1 thread stops printing for 2 -seconds at a time when the main thread is inside the lock section.

CodePudding user response:

You are not using the mutex and specially std::unique_lock properly.

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

int main()
{
     bool wnd = true;
     std::mutex mutex;

     std::thread th1{[&]() {
         for (int i = 0; i<10000;   i)
         {   std::unique_lock<std::mutex> lock(mutex);
             std::cout << i << "\tWND\t " << std::boolalpha << wnd << std::endl;
         };
     }};

     for (int i = 0; i<30;   i)
     {   std::unique_lock<std::mutex> lock(mutex);
         std::this_thread::sleep_for(std::chrono::milliseconds(2000));
         wnd = !wnd;
     }; 

     th1.join();
}

std::unique_lock uses its constructor operand as a resource whose acquisition is lock and release is unlock. It is designed to use RAII as a means of guaranteeing correct lock/unlock sequences on mutexes. a defered lock only means the mutex is not locked at the begining of lifespan of the std::unique_lock and it is not the usual use case. You can manually lock/unlock the mutex, but that generally leads to less maintainable, more error-prone code. Keep in mind that if the threads involved are not racing over the ownership of the mutex, neither waits for the other; in your original prorgram, the worker thread did not touch the mutex. But in the program above, both threads are competing to lock the mutex; winner gets a chance to continue what he wants, and the loser has to wait until the mutex is unlocked - so that he can take its ownership.

  • Related