多线程 - 线程创建
大约 4 分钟
多线程 - 线程创建
方法简概
主线程从main()开始执行,创建的线程也需要有一个初始函数
开始运行,当这个初始函数运行完毕时该线程结束
一般情况下当主线程执行完毕则其他子线程也会被强行终止(说的是thread方法,而detach线程方法可令主线程执行完毕后子线程继续执行)
线程创建方法
- 线程使用(thread对象)
- thread
- join
- detach
- joinable
- 其他创建线程的手法
- 类对象 / 匿名对象
- Lambda表达式
比较、适用场景
- 病毒软件多用detach,不然任务管理器kill掉你的主线程,子线程也都废了
基本使用
thread+join 例程
(一般用这种方式)
#include <iostream>
#include <thread> // 线程头文件
using namespace std;
void mythreadfn() // 线程的初始函数
{
cout << "子线程" << endl;
}
int main() // main函数,主线程的初始函数
{
/* (1) 分叉(创建线程)
* 创建线程并指定初始函数,此时线程开始执行了
* 这里的thread是标准库里的类,构造时传入一个可调用对象(这里是函数指针)*/
std::thread mythread(mythreadfn);
/* (2) 合并(等子线程和主线程汇合)
* 阻塞主线程,让主线程等待子线程执行完毕
* 可以避免主线程在子线程之前执行完 */
mythread.join();
cout << "主线程" << endl;
return 0;
}
thread+detach 例程
可以让主线程执行完毕后子线程继续执行
#include <iostream>
#include <thread> // 线程头文件
using namespace std;
void mythreadfn // 线程的初始函数
{
cout << "子线程" << endl;
}
int main() // main函数,主线程的初始函数
{
/* (1) 分叉(创建线程)
* 创建线程并指定初始函数,此时线程开始执行了
* 这里的thread是标准库里的类,构造时传入一个可调用对象(这里是函数指针)*/
std::thread mythread(mythreadfn);
/* (2) 分离(分离主线程不和子线程)
* 可令主线程在子线程之前执行完毕。执行后,主线程和关联的thread对象之间会失去关联
* 子线程会驻留在后台运行,相当于被C++运行时库接管。线程执行完毕时,由运行时库负责清理该线程相关的资源 */
mythread.detach();
cout << "主线程" << endl;
return 0;
}
joinable
功能:判断是否可以成功使用join()或detach()
返回true:都能使用
返回false:都不能使用
使用场景:比如之前join或detach过一遍就会返回false避免重复重复join或detach
线程入口
(1) 函数
略,如上
(2) 类对象 / 匿名对象
#include <iostream>
#include <thread> // 线程头文件
using namespace std;
class TA
{
public:
void operator()(int num) // 线程的初始函数(类成员函数)【注意这里有两个小括号】
{
cout << "子线程" << endl;
}
}
int main() // main函数,主线程的初始函数
{
Ta ta; // 类对象
/* std::thread mythread(Ta()); // 这里用匿名对象也是可以的 */
/* std::thread mythread(std::ref(ta),15); // 这里可以用引用 */
std::thread mythread(ta,15); // 函数、类、Lambda都是可调用对象
mythread.join();
cout << "主线程" << endl;
return 0;
}
(3) Lambda函数
#include <iostream>
#include <thread> // 线程头文件
using namespace std;
int main() // main函数,主线程的初始函数
{
auto mylamthread = []{
cout << "子线程" << endl;
}
std::thread mythread(mylamthread); // 函数、类、Lambda都是可调用对象
mythread.join();
cout << "主线程" << endl;
return 0;
}
(4) 成员函数指针
#include <iostream>
#include <thread> // 线程头文件
using namespace std;
class A // 要传递的类对象
{
public:
mutable int m_i;
A(int a):m_i(a){
cout<<"【构造函数】"<<endl
<<"【地址】"<<this<<endl
<<"【线程id】"<<std::this_thread:get_id()<<endl;
}
A(const A &a):m_i{
cout<<"【复制构造函数】"<<endl
<<"【地址】"<<this<<endl
<<"【线程id】"<<std::this_thread:get_id()<<endl;
}
~A(){
cout<<"【析构函数】"<<endl
<<"【地址】"<<this<<endl
<<"【线程id】"<<std::this_thread:get_id()<<endl;
}
void thread_work(int num) // 【成员函数作为线程的初始函数】
{
cout << "《子线程》" << endl
<<"《线程id》"<<std::this_thread:get_id()<<endl;
}
}
int main()
{
A aObj(10);
// 参:成员函数入口、传对象地址(不是传引用而是传地址,防止复制构造,ref()也行)、成员函数的参数
thread mythread(&A::Obj.thread_work, &aObj, 20);
mythread.join();
cout << "《主线程》" << endl
<<"《线程id》"<<std::this_thread:get_id()<<endl;
return 0;
}
- 调试结果
- 对象执行一次构造函数(主线程)、一次拷贝构造函数(子线程),两侧析构函数(主线程子线程各一次)
- 成员函数在子线程中输出
多个线程
多个线程可以用同一个线程入口函数
#include <iostream>
#include <thread> // 线程头文件
using namespace std;
void myprint(const int i)
{
cout << "《子线程》" << endl
<<"《线程id》"<<std::this_thread:get_id()<<endl;
}
int main()
{
vector <thread> mythreads; //多个线程
/* 创建10个线程,并使用同一个入口函数(线程池有2w多个,系统线程大约有5k个) */
for(int i=0; i<10; i++)
{
mythreads.push_back(thread(myprint, i));
}
/* 遍历并join */
for(auto iter=mythreads.begin(); iter!=mythreads.end(); iter++)
{
iter->join();
}
cout << "《主线程》" << endl
<<"《线程id》"<<std::this_thread:get_id()<<endl;
return 0;
}