在访问其他成员的成员线程中安全地移动运行lambda的对象

时间:2015-01-29 11:54:56

标签: c++ c++11 lambda move swap

我有一个具有std::thread成员变量的类,它运行一个依赖于其他成员变量的lambda函数。

让我举个例子:

struct C {
    C() {
        thread_ = std::thread([this]() {
            running_ = true;
            while (running_) {
                ...
            }
        });
    }
    C(C&& rv) {
        swap(rv);
    }
    void swap(C& rhs) {
        std::swap(thread_, rhs.thread_); // step 1
        std::swap(running_, rhs.running_); // step 2
    }
    std::thread thread_;
    bool running_;
};

int main() {
    C c;
    C c2 = move(c); // Is c safely moved to c2?
}
  • 移动这样一个物体的安全方法是什么?
  • 移动操作后要捕获的对象[this]
  • running_之后step 1之前的lambda中访问哪个对象step 2

1 个答案:

答案 0 :(得分:1)

虽然std::thread肯定是可移动的,但这样做并不能神奇地修改引用它的任何指针或其包含的对象(如果有的话)。

因此,即使在移动C之后,由包含的std::thread管理的线程仍将引用它之前引用的对象。

因此,如果您想安全地移动/交换C,请使用pimpl-idiom:
只安全指向线程可能访问的资源的指针,并将指针指向它 在您的情况下,这意味着:

  1. 移动running_

    struct inner {
        std::atomic<bool> running;
    };
    unique_ptr<inner> data_ = new inner;
    
  2. 传递指向数据:

    auto data = &*data_;
    thread_ = std::thread([data]() {
        data->running = true;
        while (data->running) {
            ...
        }
    });
    
  3. (也可选择移动线程未访问的数据。)

    此外,即使您没有提问,您的running也必须是std::atomic<bool>,以便检查有效。