C++ 11 - 将局部变量作为参数传递给线程时是否安全

123*_*ing 5 c++ multithreading thread-safety c++11

我有这个代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

正如您在代码中看到的那样,我尝试测试如果将局部变量传递给线程会发生什么,并且在使用它的线程之前销毁此局部变量.我发现TestParamPointer得到一个有趣的值(可能因为它现在指向垃圾值),但TestParamRef仍然得到正确的值.

所以我想知道线程是否真的将其参数存储在自己的内存中?我认为当我使用'const TestStruct&test'时,该函数不会复制整个参数,而是重用那个参数(我在param非常大时使用它 - 就像sql表的数据一样).那么它是如何工作的?将局部变量传递给线程时是否安全.

Jos*_*osh 7

std :: thread会复制或移动你传递给它的任何参数,所以是的,它是线程安全的.

另一方面,传递原始指针不是线程安全的.事实上,将指针传递给分离线程上的局部变量是非常糟糕的,因为在本地变量超出范围之前不保证线程完成(在线程完成之前,您不使用.join()来阻塞) .稍后当线程开始工作时,它可能会或可能不会有一些工作,这可能会导致崩溃.

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

线程函数的参数按值移动或复制.如果需要将引用参数传递给线程函数,则必须将其包装(例如,使用std :: ref或std :: cref).

此外,如果你使用std :: ref包装引用,通常它会变得不安全,因为它可以从原始上下文访问,所以你需要提供一个同步方法(互斥/锁,线程安全)容器或你有什么).

  • @Josh:甜蜜......只有一个挑剔:"std :: thread会复制或移动你传递给它的任何引用,所以是的,它是线程安全的" - 我建议那里有"参数"或"变量"而不是参考.代码传递`localTest`参数,不涉及调用者方引用. (2认同)