Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ 11 - Is it safe when I pass a local variable as argument into a thread

I have this code

#include <thread>

typedef struct
{
    int a;
    short b;
}TestStruct;

void TestParamRef(const TestStruct& test)
{
    Sleep(3000); /*Sleep to wait for the caller function end*/

    TestStruct i = test; /*Test if the argument's still ok*/
}

void TestParamPointer(TestStruct* test)
{
    Sleep(4000); /*Sleep to wait for the caller function end*/

    TestStruct i = *test; /*Test if the argument's still ok*/
}

void Test()
{
    TestStruct localTest; /*Local variable should be destroyed after this Test function end*/
    localTest.a = localTest.b = 69;

    std::thread threadRef(TestParamRef, localTest);
    threadRef.detach(); /*Bye bye thread*/

    localTest.a = 6969;

    std::thread threadPointer(TestParamPointer, &localTest);
    threadPointer.detach();/*Bye bye thread*/

    localTest.b = 696969;
}

int WINAPI _tWinMain(HINSTANCE  hInstance,
    HINSTANCE   hPrevInstance,
    LPTSTR      lpCmdLine,
    int     nCmdShow)
{
    Test();

    /*Put break point here*/
    return 0;
}

As you see in the code, I try to test what will happen if I pass a local variable into a thread, and this local variable is destroyed before the thread using it. And I find out that the TestParamPointer get a funny value (maybe because it's now pointing to the trash value), but the TestParamRef still get the right value.

So I wonder if the thread really store its argument in its own memory? I thought that when I use 'const TestStruct& test', the function won't copy the whole param but re-use that param (I use that when the param is pretty big - like the data of a sql table). So how did it work? Is it safe when I pass a local variable into a thread.

like image 498
123iamking Avatar asked Aug 31 '17 03:08

123iamking


1 Answers

std::thread will copy or move any argument you pass to it, so yes, it is thread safe.

Passing a raw pointer, on the other hand, is not thread-safe. In fact, passing a pointer to a local variable on a detached thread is doubly bad, because the thread is not guaranteed to complete before your local variable goes out of scope (you are not using .join() to block until thread is complete). Later on when the thread gets around to doing its work, it may or may not have something to work on, which can result in a crash.

http://en.cppreference.com/w/cpp/thread/thread/thread

The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).

Also, if you do wrap a reference using std::ref, in general it becomes unsafe, because it can be accessed from the original context, so you're going to need to provide a synchronization method (mutex/lock, thread-safe container or what have you).

like image 138
Josh Avatar answered Sep 20 '22 10:09

Josh