范例演示线程运行与开始
程序运行起来,生成一个进程,该程序所属的主线程开始运行。以下函数就是一个进程。
#include "pch.h"
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
return 0;
}
- 主线程从main()函数开始执行,我们自己创建的线程,也需要从一个函数开始运行(初函数),一旦这个函数运行完毕 ,就代表我们的线程执行完毕。
- 整个进程是否执行完毕的标志是 :主线程是否执行完毕,若果是就代表整个进程执行完毕。此时,一般情况下,若果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止。所以,一般情况下,如果想保持子线程(自己创建的线程)的运行状态的话,一定要保持主线程运行,不要其运行完毕(有例外,以后解释见detach())。
如何写自己的线程:
thread
thread标准库里的类,myprint可调用对象,创建子线程,线程执行起点,线程开始执行。
join()
加入/汇合,术语阻塞,阻塞主线程,让主线程等待子线程执行完毕,然后子线程与主线程汇合,join执行完毕,主线程继续执行
- 包含一个头文件t#include < thread >;
- 初始函数;
- main()中写代码;如下:
#include "pch.h"
#include <iostream>
#include<thread>
void myprint()
{
std::cout << "子线程开始执行。" << std::endl;
//....
//....
std::cout << "子线程执行完毕。" << std::endl;
}
int main()
{
std::thread mytobj(myprint);//thread标准库里的类,myprint可调用对象,创建子线程,线程执行起点,线程开始执行。
mytobj.join(); //join()加入/汇合,术语阻塞,阻塞主线程,让主线程等待子线程执行完毕,然后子线程与主线程汇合,join执行完毕,主线程继续执行
std::cout << "主线程安全退出!" << std::endl;
return 0;
}
注意,此程序包含两个线程,即同事做两个任务,一个任务被阻止,另一个可以继续执行。join很重要,没有join程序报错,程序执行混乱;不能保证子线程在主线程之前结束。
detach()
a.传统多线程程序要等子线程执行完毕,然后自己在退出;detach():分离也就是主线程与子线程不汇合,各执行各的,不必等待;
b.为什么引入:我们创建很多子线程,让主线程逐个等待子线程结束,这种编程不太好,所以引入detach()一旦detach()后,与主线程关联的thread对象就会失去关联,子线程驻留在后台运行,被c++运行时库接管-建议少用
#include "pch.h"
#include <iostream>
#include<thread>
void myprint()
{
std::cout << "子线程开始执行。" << std::endl;
// ...
//....
std::cout << "子线程执行完毕1。" << std::endl;
std::cout << "子线程执行完毕2。" << std::endl;
std::cout << "子线程执行完毕3。" << std::endl;
std::cout << "子线程执行完毕4。" << std::endl;
std::cout << "子线程执行完毕5。" << std::endl;
std::cout << "子线程执行完毕6。" << std::endl;
std::cout << "子线程执行完毕7。" << std::endl;
std::cout << "子线程执行完毕8。" << std::endl;
std::cout << "子线程执行完毕9。" << std::endl;
std::cout << "子线程执行完毕10。" << std::endl;
}
int main()
{
std::thread mytobj(myprint);
mytobj.detach();
std::cout << "主线程执行完毕。" << std::endl;
return 0;
}
两次运行结果不一致,detach()会导致子线程失去控制,建议少用。一旦detach()后,不能join(),程序会报错。
joinable()
判断是否成功使用join()或detach(),成功返回false,否则返回else。
#include "pch.h"
#include <iostream>
#include<thread>
void myprint()
{
std::cout << "子线程开始执行。" << std::endl;
// ...
//....
std::cout << "子线程执行完毕1。" << std::endl;
std::cout << "子线程执行完毕2。" << std::endl;
std::cout << "子线程执行完毕3。" << std::endl;
std::cout << "子线程执行完毕4。" << std::endl;
std::cout << "子线程执行完毕5。" << std::endl;
std::cout << "子线程执行完毕6。" << std::endl;
std::cout << "子线程执行完毕7。" << std::endl;
std::cout << "子线程执行完毕8。" << std::endl;
std::cout << "子线程执行完毕9。" << std::endl;
std::cout << "子线程执行完毕10。" << std::endl;
}
int main()
{
std::thread mytobj(myprint);
if (mytobj.joinable())
{
std::cout << "joinable()==true" << std::endl;
}
else
{
std::cout << "joinable()==false" << std::endl;
}
mytobj.detach();
if (mytobj.joinable())
{
std::cout << "joinable()==true" << std::endl;
}
else
{
std::cout << "joinable()==false" << std::endl;
}
std::cout << "主线程执行完毕。" << std::endl;
return 0;
}
其他创建线程的方法
用类以及一个问题范例
#include "pch.h"
#include <iostream>
#include <thread>
class TA
{
public:
void operator()() //
{
std::cout << "子线程开始执行。" << std::endl;
//....
std::cout << "子线程执行完毕。" << std::endl;
}
};
int main()
{
TA ta;
std::thread mytobj2(ta);
mytobj2.join();
std::cout << "主线程执行完毕。" << std::endl;
return 0;
}
疑问:一旦调用detach(),那主线程就结束了,这里用的ta对象还存在吗?
答:对象不存在,但是被复制到线程中去,执行完主线程后,ta被销毁,但所复制的对象依旧存在。所以,只要这个TA类对象里没有引用,没有指针,就不会产生问题。
用lambda表达式
#include "pch.h"
#include <iostream>
#include <thread>
int main()
{/*
TA ta;
std::thread mytobj2(ta);
mytobj2.join();*/
auto mylamthread = [] {
std::cout << "我的线程开始执行。" << std::endl;
//...
std::cout << "我的线程执行完毕。" << std::endl;
};
std::thread mytobj4(mylamthread);
mytobj4.join();
std::cout << "主线程执行完毕。" << std::endl;
return 0;
}