初涉线程
线程的开始
主线程从main函数开始,自己创建的线程则需要提供一个可调用对象。函数执行完毕,线程就退出。
线程的结束
主线程退出后,整个进程也将执行完毕。
一般情况下,如果其它子线程也还没执行完毕,随着主线程退出,子线程也将被操作系统全部中止。
线程头文件
#include <thread>
thread类介绍
- join()函数,阻塞主线程,主线程等待子线程执行完毕。
- detach()函数,分离子线程,使得子线程在后台运行(类似于守护线程)。一旦detach,主线程与子线程失去关联。子线程将被运行时库接管。
- joinable()函数,返回bool值。判断是否可以join或detach。每个线程只能join或者detach一次。
#include "stdafx.h"
#include <iostream>
#include <thread>
void func() {
std::cout << "这是一个新线程" << std::endl;
}
int main()
{
std::thread t(func);
t.join();
//t.detach();
if (t.joinable() == true)
{
std::cout << "线程 t 可以 join或者detach " << std::endl;
}
else {
std::cout << "线程 t 不可以 join或者detach " << std::endl;
}
return 0;
}
使用仿函数构造线程对象
注意:下面示例输出说明构造线程对象的可调用对象被拷贝到线程的堆栈空间。所以可调用对象拷贝构造函数将被调用。这就是detach情况下,主线程在子线程之前退出,不会因为局部对象被析构而导致异常的原因。。
示例:
class TestObj {
public:
TestObj() {
std::cout << "构造函数被调用" << std::endl;
}
TestObj(const TestObj& obj)
{
std::cout << "拷贝构造函数被调用" << std::endl;
}
~TestObj()
{
std::cout << "析构函数被调用" << std::endl;
}
void func(){
}
void operator()() {
std::cout << "线程开始了:TestObj" << std::endl;
std::cout << "线程结束了:TestObj" << std::endl;
}
};
int main()
{
TestObj obj;
std::thread t(obj);
std::thread t2(&TestObj::func,&obj/*使用引用才能使用同一个对象,否则对象会被拷贝。*/);
t.join();
std::cout << "主线程退出" << std::endl;
return 0;
}
输出:
构造函数被调用
拷贝构造函数被调用
线程开始了:TestObj
线程结束了:TestObj
析构函数被调用
主线程退出
析构函数被调用
使用lambda函数构造线程对象
- 传参示例1:
std::thread t([] {
std::cout << "线程开始了:lambda" << std::endl;
std::cout << "线程结束了:lambda" << std::endl;
});
传参示例2:
auto myLambda = [] {
std::cout << "线程开始了:lambda" << std::endl;
std::cout << "线程结束了:lambda" << std::endl;
};
std::thread t(myLambda);