2

The following code (under Visual Studio 2013) fails in the assert. Can someone explain why this happens?

#include <thread>
#include <cassert>

std::thread t;

void threadTask()
{
   assert(t.get_id() == std::this_thread::get_id());
}

int main()
{
    for (int i = 0; i < 1000; ++i)
    {
        t = std::thread(threadTask);
        t.join();
    }
}

I'm looking for a way to check that a function is called from a specified thread.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065

1 Answers1

7

The thread can start running before the std::thread constructor exits back to the caller, so the assert() is likely being called before the t variable is assigned a new value. On the first loop iteration, that means t could be undefined. On subsequent iterations, it means t could still be referring to the previous thread.

The thread needs to wait until t is assigned a value before it can use t reliably. For example, by protecting t with a std::mutex:

#include <thread>
#include <mutex>
#include <cassert>

std::thread t;
std::mutex m;

void threadTask()
{
   {
   std::lock_guard<std::mutex> l(m);
   assert(t.get_id() == std::this_thread::get_id());
   }
   ...
}

int main()
{
    for (int i = 0; i < 1000; ++i)
    {
        {
        std::lock_guard<std::mutex> l(m);
        t = std::thread(threadTask);
        }
        t.join();
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks! Indeed looks like this is true. Is there a way to ensure that `t` is assigned prior to thread beginning execution? – Greg Ravikovich Oct 29 '16 at 18:18
  • @GregRavikovich: Instead of a parameterless function and passing things on a side, just use `std::thread` with a function with parameters. See ie. http://stackoverflow.com/questions/20340750/pass-multiple-arguments-into-stdthread – quetzalcoatl Oct 29 '16 at 18:23
  • @quetzalcoatl that does not address the race condition in this situation. It could be used to pass around a pointer/reference to the `t` variable, but the variable itself still needs to be assigned and accessed in a thread-safe manner to ensure accuracy. – Remy Lebeau Oct 29 '16 at 18:26
  • @Remy: yes, indeed. You have answered it well. However, what I wrote addresses the issue in much simpler way. I bet the author created the global variable only because he did not know about parameters. If he had used parameters, then he would not have the problem at all. – quetzalcoatl Oct 29 '16 at 18:27
  • @Remy: ah, of course. If you start adding pointers and references to random places, then even with added mutexes you can still shoot yourself in the foot. – quetzalcoatl Oct 29 '16 at 18:28