启动线程
同上节所讲,线程是通过构造std::thread对象来开始的:
void do_some_work();
std::thread my_thread(do_some_work);
使用可调用类型:
#include<iostream>
#include<thread>
class func {
public:
void operator()() {
std::cout << "hello thread" << std::endl;
}
};
int main() {
func fun;
std::thread t(fun);
t.join();
system("pause");
}
等待线程完成
如果你不做处理,在主线程结束后,thread对象管理的线程也被结束了,通过调用thread.detach()使线程不被销毁,或使用join()使主线程等待其他线程的结束。
使用RAII(资源获取即初始化)等待线程完成:
#include<iostream>
#include<windows.h>
#include<thread>
class func {
public:
void operator()() {
Sleep(1000);
std::cout << "hello thread" << std::endl;
}
};
class thread_guard {
std::thread& t;
public:
explicit thread_guard(std::thread& t_) :t(t_) {}
~thread_guard() {
if (t.joinable()) {
t.join();
}
}
};
int main() {
func fun;
std::thread t(fun);
thread_guard g(t);
system("pause");
return 0;
}
传递参数给线程函数
使用std::ref()包装需要引用的参数:
void f(int i, int& j) {
i++;
j++;
}
int main() {
int i = 10;
int j = 10;
std::thread t(f,i,std::ref(j));
t.join();
std::cout << "i:" << i << std::endl
<< "j:" << j << std::endl; //输出i:10 j:11
system("pause");
return 0;
}
转移线程的所有权
同其他拥有资源的类型(std:;ifstream和std::unique_ptr)一样std::thread是可移动的而非可复制的。
以下改进thread_guard类,使它实际上获得线程的所有权,这就能避免其他对象结合或分离该线程:
class scoped_thread
{
std::thread t;
public:
explicit scoped_thread(std::thread t_)
: t(std::move(t_))
{
if (!t.joinable())
{
throw std::logic_error("No thread");
}
}
~scoped_thread()
{
t.join();
}
scoped_thread(scoped_thread&) = delete;
scoped_thread& operator=(scoped_thread const &) = delete;
};
void fun() {
std::cout << std::this_thread::get_id() << std::endl;
}
int main()
{
scoped_thread tt(std::thread{ fun }); //这里使用大括号而不是小括号来避免c++将其视为函数声明
//scoped_thread t(std::thread([] //也可以使用lambda表达式来避免
//{
// std::cout << std::this_thread::get_id() << std::endl;
//}));
system("pause");
return 0;
}
其他
//获取机器真正并行线程数指标,信息不可用则返回0
std::cout << std::thread::hardware_concurrency() << std::endl;
//获取线程标识
//1、当前线程的标识符
std::this_thread::get_id()
//2、通过线程对象的成员函数获得
t.get_id()