一:范例 线程运行的开始和结束
1.1 先写一个最简单的程序:
#include <iostream>//输入输出头文件
// 程序运行起来,生成一个进程,该进程所属的主线程自动运行。
int main()
{
std::cout << "I LOVE CHINA!" << std::endl;//实际上这个是主线程执行。
return 0;
}
非常简单,就是开启了一个进程,主线程从main函数开始执行,最后主线程结束退出。
1.2 自己创建线程(子线程)方法:
- 包含头文件thread;
- 创建一个函数入口;
- 写代码。
// 主线程从main函数开始执行,那我们自己创建的线程,
//也需要从一个函数开始运行(初始函数),
//一旦此函数运行完毕, 就代表此线程运行结束
#include <iostream>//输入输出头文件
#include <thread>//包含线程头文件
using namespace std;
// 自己创建的线程也要从一个函数运行(函数入口)
void myprint()
{
cout << "我的线程开始了。。。。。" << endl;
cout << "我的线程结束了。。。。" << endl;
}
int main()
{
//创建子线程的具体代码
//thread 是标准库里的类
thread myobj(myprint);// myprint可调用对象。创建了线程,线程起点myprint,并开始执行。
//阻塞主线程,让主线程等待子线程执行完毕,
//然后子线程和主线程汇合,然后主线程继续。
myobj.join(); // 主线程等待子线程(myprint)执行完毕,两者汇合后继续。
//detach():传统多线程程序要主线程等到子线程完毕,然后主线程结束。
//myobj.detach();//这条语句的效果可以多运行几次看结果差异。
cout << "我是主线程,我要安全退出了!" << endl;
return 0;
}
运行结果如下:
如果用
d
e
t
a
c
h
(
)
detach()
detach()的话:
这说明
d
e
t
a
c
h
(
)
detach()
detach()并没有要求主线程等待子线程执行完再退出。
detach: 主线程不与子线程汇合,各自走各自的路,不必等子线程运行结束了。
为啥要引入这种机制?如果子线程太多,主线程非得等每个都执行完,也不是很好。(建议不要用detach)
一旦detach之后,与主线程关联的thread对象就会失去与主线程关联,此时子线程就会驻留在系统后台运行。
子线程就相当于被c++运行时库接管,当子线程执行完毕时,由运行时库负责清理该线程的相关资源(守护线程)。
detach使子线程失去了控制,一旦detach了就无法再join回来了。
再来介绍一下 j o i n a b l e ( ) joinable() joinable(),他是为了判断是否可以成功使用join()或detach()。
if (myobj.joinable())//返回true或false
{
cout << "joinable == true.\n" << endl;//如果前面没join过
myobj.join();
}
二、其他创建线程的方法
2.1 用类可调用对象
#include <iostream>//输入输出头文件
#include <thread>//包含线程头文件
using namespace std;
//用类创建入口
class TA
{
public:
void operator()()//重载括号运算符,可调用函数
{
cout << "我的线程operator()开始了。。。。。" << endl;
cout << "我的线程operator()结束了。。。。。" << endl;
}
};
int main()
{
//创建子线程的具体代码
TA ta;//创建一个类对象
//thread 是标准库里的类
thread myobj1(ta);// ta可调用对象。创建了线程,线程起点重载函数(),并开始执行。
//阻塞主线程,让主线程等待子线程执行完毕,
//然后子线程和主线程汇合,然后主线程继续。
myobj1.join(); // 主线程等待子线程重载函数()执行完毕,两者汇合后继续。
//detach():传统多线程程序要主线程等到子线程完毕,然后主线程结束。
//myobj.detach();//这条语句的效果可以多运行几次看结果差异。
cout << "我是主线程,我要安全退出了!" << endl;
return 0;
}
运行结果如下:
上面有一个问题,如果调用了detach,主线程结束后这个ta还在吗?(不在了)那子线程怎么运行呢?(这个对象实际上是被复制到子线程去,复制的依旧存在)。
怎么证明这个对象是被复制进去的呢?
我们可以打印出
t
a
ta
ta 在主线程和子线程中分别的地址验证。
在我的机器上:
可以看出两者地址不一样,子线程中的对象是复制的存在。
2.2 用lamada表达式
auto mylamdathread = [] {
cout << "线程3开始执行了!" << endl;
cout << "线程3结束执行了!" << endl;
};
thread mytobj4(mylamdathread);
mytobj4.join();
运行结果如下: