默认情况下,线程入口函数都是通过拷贝的方式将值传入而不管线程入口函数带的参数是值类型还是引用类型。很奇怪,不能理解么,那请看下边代码,让我们一一理清:
//-----------main.cpp
#include <iostream>
#include <functional>
#include <thread>
void f1(int n)
{
for (int i = 0; i < 5; ++i)
{
std::cout << "Thread1 executing." << std::endl;
++n;
}
}
void f2(int &n)
{
for (int i = 0; i < 3; ++i)
{
std::cout << "Thread2 executing." << std::endl;
++n;
}
}
int main()
{
int n = 0;
std::thread t1(f1, n); // pass by value.
// 为了真正做到引用传递,必须用std::ref来包裹一层,否则编译不通过
// 即使编译通过,也达不到我们想要的输出效果哦。
std::thread t2(f2, std::ref(n)); // pass by reference.
t1.join();
t2.join();
std::cout << "Final value of n is " << n << std::endl;
return 0;
}
输出结果如下:
Thread1 executing.
Thread1 executing.
Thread1 executing.
Thread1 executing.
Thread1 executing.
Thread2 executing.
Thread2 executing.
Thread2 executing.
Final value of n is 3
我们需要注意的是,按值传递有一种坑,在这里我们需要说明一下,这里涉及到隐式转换的问题,请看下边的例子:
//-----------main.cpp
#include <iostream>
#include <string>
#include <thread>
void f1(int n, const std::string& str)
{
std::cout << "str = " << str << std::endl;
}
void f2(int num)
{
char buffer[1024] = { 0 };
sprintf(buffer, "%i",num);
std::thread t1(f1, 3, buffer);
t1.detach();
}
int main()
{
f2(9);
return 0;
}
这段代码,开启一个新线程后,立即将线程置为detached的状态,将指向本地局部变量buffer的指针传递给新线程,这样就可能存在一个问题,buffer在新线程上还没有转换成为std::string类型,f2函数就退出了,这样读取到的buffer值是不确定的,因而会导致不确定的行为。为避免这种情况,我们可以在传入给线程函数之前,使用std::string 来进行显示转换,如下所示:
void f2(int num)
{
char buffer[1024] = { 0 };
sprintf(buffer, "%i",num);
std::thread t1(f1, 3, std::string(buffer)); // Using std::string avoids dangling pointer
t1.detach();
}
下面介绍另一种启动线程的方式, 如果你熟悉C++11标准库std::bind函数的机制,那么你对下边的使用方式,就不会陌生,因为std::thread 的构造函数和std::bind的操作实现机理是一样的,请看代码:
//-----------main.cpp
#include <iostream>
#include <string>
#include <thread>
class X
{
public:
void Print(int num)
{
std::cout << "num = " << num << std::endl;
}
};
int main()
{
// 调用方式
X my_x;
std::thread t(&X::Print, &my_x, 9);
t.join();
std::cout << "Hello World!" << std::endl;
return 0;
}
上述代码表示,在新线程中会执行类似my_x.Print(9)形式调用的功能。其中传递了成员函数指针给thread作为线程入口函数,X类对象指针作为第一个参数,从该对象指针之后的参数,可依次做为成员函数Print的参数。