【问题标题】:c++11 functor within thread puzzle线程谜题中的c ++ 11函子
【发布时间】:2012-01-25 10:46:40
【问题描述】:

请考虑以下代码 sn-p。使用 GCC 4.6.1,x 变为 0y 变为 1

为什么使用和不使用单独的线程会得到不同的结果?我应该如何修改代码,以便两个版本产生相同的结果(即整数值增加 1?)

谢谢。

struct functor{
    void operator()(int & x){
        ++x;
    }    
};

void tfunc(functor & f, int & x){
    f(x);
}

int main(){
    functor f;
    int x = 0, y = 0;
    std::thread t = std::thread(tfunc, f, x);
    t.join();
    std::cout << "with thread " << x << std::endl;    
    f(y);
    std::cout << "without thread " << y << std::endl;
}

【问题讨论】:

  • 尝试使x 不稳定。编译器在创建std::thread 之后但在join 返回之前获取其值是合法的。
  • @spraff: volatile 不能替代正确的同步(这也不是同步问题)。
  • 更新。如果将int * 传递给tfunc 而不是int &amp;,它就可以工作。很奇怪。

标签: c++ multithreading c++11 functor


【解决方案1】:

很容易看到发生了什么。只需将int 替换为不可复制的类型(带有私有复制构造函数的类型),编译器就会确定libstdc++ 尝试复制参数而不是使用引用的确切位置。在我的情况下,它是 &lt;tuple&gt; 标准标头中的第 138 行。

这是否是标准的正确实施,我目前无法判断。

更新 标准规定std::thread::thread 的每个参数都应满足MoveConstructible 要求,并且传递给线程函数的实际参数是从std::thread::thread 参数移动构造的。这意味着

  1. 线程函数获取参数的副本,并且
  2. 原件很可能在处理过程中被销毁。

所以通过引用传递东西是行不通的。

【讨论】:

  • 在这种情况下,我想解决方案是针对std::thread 的实现添加重载以将引用参数包装在std::ref 中,对吧?
  • @spraff:不需要修复——std::thread 已经处理了 std::ref。如果您将程序更改为std::thread t = std::thread(tfunc, f, std::ref(x));,它就可以工作。这正是std::ref 存在的那种情况。
【解决方案2】:

看起来当std::thread(tfunc, f, x)被调用时,x被复制并且对临时值的引用被传递到函子,因此对函子的调用不会改变x的值。我认为一般 STL 算法/函数总是复制参数。如果你想让你的函子调用改变 x,你可以考虑使用指针,因为即使复制了一个指针,副本仍然指向相同的地址。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-24
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    相关资源
    最近更新 更多