在c ++ 11中使用带有std :: thread的atomics

Mat*_*ine 7 c++ multithreading gcc atomic c++11

我有一个线程,我想坐在循环中,直到我准备退出程序,此时我希望它突破循环并退出所以我可以调用std::thread::join它.在c ++ 03的时代,我只会使用一个受锁保护的bool来告诉线程什么时候退出.这次我以为我会利用新的原子库(特别是std::atomic_bool),但我遇到了麻烦.以下是我的测试用例:

#include <atomic>
#include <thread>
#include <cstdio>

using namespace std;

void setBool(atomic_bool& ab)
{
    ab = true;
}

int main()
{
    atomic_bool b;
    b = false;
    thread t(setBool, b);
    t.join();
    printf("Atomic bool value: %d\n", b.load());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译时,宣布thread t吐出这种怪异.错误的核心部分似乎是:

从'std :: atomic_bool'类型的右值开始无效初始化'std :: atomic_bool&'类型的非const引用

为什么我不能参考atomic_bool?我该怎么做呢?

inf*_*inf 13

您必须显式地将ref传递给您的线程.使用std::ref将创建一个std::reference_wrapper可复制的,并将ref带到您的功能.

thread t(setBool, std::ref(b));
Run Code Online (Sandbox Code Playgroud)

否则它会尝试复制你的原子,这是不可复制的.

  • @ slavik262是的,这是真的.线程构造函数执行此操作,因为您正在调用一个您不知道何时执行的函数,如果您传递了引用,该引用可能无效,因此它将复制您的参数以安全地存储它们.如果明确使用ref-wrapper,那么确保该对象比线程更长是你的工作. (5认同)

Kno*_*abe 5

正如Bamboon所解释的,std::ref如果确实希望通过std::thread变量参数构造函数通过引用传递对象,则必须使用包装对象。(同样适用于std::async。)为避免这种违反直觉的行为,可以使用lambda,该lambda的行为与您期望的完全一样。只需使用它来创建线程:

thread t([&]{ setBool(b); });
Run Code Online (Sandbox Code Playgroud)

对于lambda,当您想通过引用传递参数时,不需要ref / cref废话。