简体   繁体   English

指针和引用之间的区别(作为线程参数)

[英]Difference between pointer and reference as thread parameter

This is the example: 这是示例:

#include<iostream>
#include<thread>
using namespace std;

void f1(double& ret) {
   ret=5.;
}

void f2(double* ret) {
   *ret=5.;
}

int main() {
   double ret=0.;
   thread t1(f1, ret);
   t1.join();
   cout << "ret=" << ret << endl;
   thread t2(f2, &ret);
   t2.join();
   cout << "ret=" << ret << endl;   
}

And the output is: 输出为:

ret=0
ret=5

Compiled with gcc 4.5.2, with and without -O2 flag. 使用gcc 4.5.2编译,带有和不带有-O2标志。

Is this expected behavior? 这是预期的行为吗?

Is this program data race free? 该程序数据竞赛免费吗?

Thank you 谢谢

The constructor of std::thread deduces argument types and stores copies of them by value. std::thread的构造函数推导参数类型并按值存储它们的副本。 This is needed to ensure the lifetime of the argument object is at least the same as that of the thread. 这需要确保自变量对象的生存期至少与线程的生存期相同。

C++ template function argument type deduction mechanism deduces type T from an argument of type T& . C ++模板函数参数类型推导机制从类型T&的参数推导类型T All arguments to std::thread are copied and then passed to the thread function so that f1() and f2() always use that copy. 复制std::thread所有参数,然后将其传递给线程函数,以便f1()f2()始终使用该副本。

If you insist on using a reference, wrap the argument using boost::ref() or std::ref() : 如果您坚持使用引用,请使用boost::ref()std::ref()包装参数:

thread t1(f1, boost::ref(ret));

Or, if you prefer simplicity, pass a pointer. 或者,如果您更喜欢简单性,请传递一个指针。 This is what boost::ref() or std::ref() do for you behind the scene. 这就是boost::ref()std::ref()在幕后为您做的事情。

That you are required an explicit std::ref() (or boost::ref() ) in these situations is actually a very useful safety feature as passing a reference can be by nature a dangerous thing to do. 在这种情况下,您需要显式的std::ref() (或boost::ref() )实际上是非常有用的安全功能,因为传递引用本质上是一件危险的事情。

With a non-const reference there is quite often a danger that you are passing in a local variable, with a const-reference it might be a temporary, and as you are creating a function to be called in a different thread (and with bind in general, often a function to be called later / in an asynchronous way) you will have the big danger of the object being no longer valid. 使用非const引用时,通常存在传递本地变量的危险,使用const引用时,它可能是临时的,并且在创建要在其他线程中调用的函数时(以及使用bind时)通常,通常是一个以后要用异步方式调用的函数),您将面临对象不再有效的巨大危险。

binding looks tidy but these bugs are the hardest to find, as where the error is caught (ie in calling the function) is not the same place that the error was made (at the time of binding) and it can be very hard to work out exactly which function is being called at the time, and therefore where it was bound. 绑定看起来很整洁,但是这些错误是最难发现的,因为捕获错误的位置(即调用函数)与发生错误的位置不同(绑定时),并且很难处理确切地指出当时正在调用哪个函数,以及它的绑定位置。

It is safe in your instance as you join the thread in the scope of the variable you are passing as reference. 在将线程作为引用传递的变量范围内加入线程时,在您的实例中是安全的。 Therefore when you know that to be the case there is a mechanism for passing a reference. 因此,当您知道这种情况时,就有一种传递引用的机制。

It is not a feature of the language I would like to see changed, particularly as there is probably a lot of existing code relying on it making a copy that would break if it just took by reference automatically (and would then need an explicit way to force a copy). 这不是我希望看到的语言功能的变化,特别是因为可能有很多现有代码依赖它来制作副本,如果仅自动引用它就会破坏副本(然后需要一种明确的方式来实现)强制复制)。

If you want to pass parameters by reference to a std::thread you must enclose each of them in std::ref : 如果要通过引用传递给std::thread参数,则必须将每个参数都包含在std::ref

thread t1(f1, std::ref(ret));

More info here . 更多信息在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM