启动一个线程
#include <iostream>
#include <thread>
int main()
{
std::cout << "thread starting..." << std::endl;
std::thread myThread([]{
std::cout<<"this is a new thread!"<< std::endl;
});
myThread.join();
return 0;
}
运行结果:
thread starting…
this is a new thread!
要点:
- std::thread的构造可传入一切callable对象,如: 普通函数、lambda、函数指针、bind对象、拥有()符号重载的函数对象。
- 你一定要确保在std::thread对象被销毁前(而不是线程结束前)显式地调用std::thread对象的 join 或 detach方法。
- std::thread对象被销毁并不代表线程一定结束了。特别是当你调用了detach之后,当该thread对象被销毁,线程很可能还在运行中。
- 如果你调用detach分离线程,那么应当确保线程所需要访问的数据是有效的。 特别注意局部变量。
- join的作用是当前线程等待其对应的子线程结束之后才会结束,可以有效防止子线程对局部变量的依赖风险。detach的作用是将指定的子线程从当前线程中分离,当前线程不再等待该线程执行完毕才结束,同时相当于是放弃了对该线程的控制权,再也无法获得该线程的对象并对其进行通讯或控制。
- join 会阻塞主(父)线程的执行,考虑以下代码:
#include <iostream>
#include <thread>
#include <chrono>
int main()
{
std::thread thread1([]{
std::cout<<"thread1 started"<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<<"thread1 end!" << std::endl;
});
thread1.join();
std::thread thread2([]{
std::cout<<"thread2 started"<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<<"thread2 end!" << std::endl;
});
thread2.join();
std::cout<<"after join";
//myThread.detach();
return 0;
}
当main输出after join时,实际上等待了6秒,即 thread1.join() 阻塞主线程等待thread1执行完成后才开始向下执行。
#include <iostream>
#include <thread>
#include <chrono>
int main()
{
std::thread thread1([]{
std::cout<<"thread1 started"<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<<"thread1 end!" << std::endl;
});
std::thread thread2([]{
std::cout<<"thread2 started"<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<<"thread2 end!" << std::endl;
});
thread1.join();
thread2.join();
std::cout<<"after join";
//myThread.detach();
return 0;
}
把thread1.join()放到thread2.join()之前则 main输出after join时总共只等待了3秒。以上例子同时还说明了std::thread的执行实际上在thread对象构造的时候就已经开始,而不是等到join或者detach被调用才开始(但并不保证构造语句执行后线程就一定成功跑起来了,有可能会延时)。
给新线程传递参数
实际上就是给thread对象绑定的函数传递参数:
#include <iostream>
#include <thread>
#include <chrono>
#include <functional>
#include <mutex>
std::mutex g_mutex;
int main()
{
auto func = [](int id){
g_mutex.lock();
std::cout<<"thread"<< id <<" started"<< std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<<"thread"<< id <<" end!" << std::endl;
g_mutex.unlock();
};
std::thread thread1(func,1);
std::thread thread2(func,2);
thread1.join();
thread2.join();
std::cout<<"after join";
//myThread.detach();
return 0;
}
运行结果:
thread1 started
thread1 end!
thread2 started
thread2 end!
after join
给线程传递引用
以下代码编译会报错:
#include <iostream>
#include <thread>
using namespace std;
foo(int& val){
val = 123;
}
int main()
{
int num = 0;
thread (foo,num).join();
return 0;
}
原因是c++默认会把线程实参进行拷贝,即在子线程中访问到的引用实际上已经是副本的引用,依然改变不了原变量,所以这是没有意义的。笔者目前的编译器版本(gcc version 4.9.2)会对以上代码报错。
解决方案是 对实参加上 std::ref();
#include <iostream>
#include <thread>
using namespace std;
foo(int& val){
val = 123;
}
int main()
{
int num = 0;
thread (foo,ref(num)).join();
return 0;
}
即可完美运行。