一 范例演示线程的创建
1.thread 类
前面的内容知道,程序运行起来,生成一个进程,该进程所属的主线程从main方法开始自动运行直到return 结束。
我们创建一个线程,也要从一个函数开始运行,一旦这个函数运行起来,就代表着我们这个线程开始运行,一旦这个函数运行结束,就代表着这个线程运行结束。
C++11提供了thread 这个类,因此第一步就是要 #include <thread>
使用 thread 类 ,构建对象的时候,传递的参数是一个方法,我们这里 是:mythreadmethod().
暂时没有传递参数。
我们知道,当主线程执行完毕后,进程也就挂了。如果主线程都执行完毕了,子线程还没有执行完毕,那么一般情况下,进程就会有runtime exception。
因此,在一般情况下,我们要让主线程等待子进程结束。因而引出了join()方法的使用
// 002createthread_join_detach.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <thread>
using namespace std;
void mythreadmethod() {
cout << "mythreadmethod start..." << endl;
cout << "mythreadmethod end..." << endl;
}
int main()
{
std::cout << "Hello World start!\n";
thread mythread(mythreadmethod);//这句话的意思是:1.创建一个子线程;2.该线程执行起点是mythreadmethod方法;3.mythreadmethod方法就已经抢占CPU开始执行,但是并不一定能抢过其他线程。
mythread.join();//join方法的意思是:作用是阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后再沿着主线程没有完成代码往下走。
std::cout << "Hello World end!\n";
}
2.join()
作用是阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后再沿着主线程没有完成代码往下走。
2.1 主线程阻塞等待,直到子线程执行完毕
2.2 子线程只能就算执行完毕了呢?就是创建子线程时,传递的方法 执行 完成了
2.3 不加 join()方法会怎么样呢?不会编辑错误,但是运行时候,会有几率 runtime exception。
原因也很简单,当主线程先于子线程执行完成的case发生的时候:
主线程结束 = 进程结束
但是这时候子线程没有结束,那么这时候子线程依附于谁存在呢?换句话说:子线程中的临时变量,方法等,谁来回收呢?因此就有runtime exception
3.detach() 老师不建议使用,坑太多,除非有必要,
从上面知道,传统多线程程序:主线程使用join()方法等到子线程执行完毕,然后再执行自己的逻辑。
那么能不能主线程自己结束就结束,不用管子线程呢?
detach()方法就是干这个的。
使用detach()的意思是:
3.1主线程不和子线程汇合了
3.2子线程原本关联的主线程,现在就不在和主线程关联了,这个子线程就会驻留在后台运行。
3.3该子线程会被C++运行时库接管,当子线程执行完毕后,由运行时库(实际上是守护线程,这个要知道linux的一些相关进程线程的知识才懂,如果不懂,就大致理解为有人接管就可以了)清理该线程相关资源
3.4 detach 的坑 - 后续章节上专门研究
当主线程结束的时候,主线程中的值能否使用?
如果线程对象传递的方法中有参数,且这个参数是从主线程传递过去的,当主线程运行结束后,那么这个参数能否使用?
4.joinable()
该函数的作用是判断,join()或者 detach()方法能否使用?
运用时机:当程序很大的,最好判断一下。
结论:
当使用了join方法后,就不能再次使用join 和 detach方法了
当使用了detach方法后,就不能再次使用join 和 detach方法了
5. 如果join 和 detach都不写,会怎么样呢?
会runtime exception,原因未知。
二 用类创建线程以及注意问题
1.使用类对象,这个类对象需要实现operator()()方法,即()的重载。
class AA {
public:
void operator()() {
cout << "class AA operator()() start..." << endl;
cout << "class AA operator()() end..." << endl;
}
int age;
};
//运行结果为:
//Hello World0 start!
//class AA operator()() start...Hello World1 end!
// Hello World2 end!
// Hello World3 end!
// Hello World4 end!
//
// class AA operator()() end...
// Hello World5 end!
// Hello World6 end!
void main() {
AA aa;
std::cout << "Hello World0 start!\n";
thread mythread(aa);
std::cout << "Hello World1 end!\n";
std::cout << "Hello World2 end!\n";
std::cout << "Hello World3 end!\n";
std::cout << "Hello World4 end!\n";
mythread.join();
std::cout << "Hello World5 end!\n";
std::cout << "Hello World6 end!\n";
}
//创建线程的方法,使用operator()函数做为 线程的入口函数
class Teacher141 {
public:
void operator()() {
for (int i = 0; i < 10;i++) {
cout << "Teacher141 的 operator() 没有参数的方法被调用" << endl;
}
}
void operator()(int num ) {
for (int i = 0; i < 10;i++) {
cout << "Teacher141 的 operator(int num) 的方法被调用: num = " << num << endl;
}
}
void Teacher141func(int num) {
m_age = num;
cout << "Teacher141 的 operator() 没有参数的方法被调用" << endl;
}
int m_age;
};
//operator()()做thread 启动方法入口
void main() {
cout << " test thread start " << endl;
//operator()()做thread 启动参数
Teacher141 t1;
thread mythread1(t1);
//operator()(T t)做thread 启动参数
Teacher141 t2;
thread mythread12(t2,20);
mythread1.join();
mythread12.join();
//test thread start
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用Teacher141 的 operator(int num) 的方法被调用: num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator(int num) 的方法被调用 : num = 20
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// Teacher141 的 operator() 没有参数的方法被调用
// test thread end
cout << " test thread end " << endl;
}
2.使用类的成员函数来作为 线程的入口函数。
//类的成员函数做 线程启动函数入口
class Teacher142 {
public:
void writeTeacherName() {
for (int i = 0; i < 1000; i++) {
cout << " 子线程id 为 : " << this_thread::get_id() << " i = " << i << endl;
}
}
};
void main() {
Teacher142 tea;
int a = 10;
thread mythread(&Teacher142::writeTeacherName,&tea);
for (int i = 0; i < 1000;i++) {
cout << "主线程id 为 : " << this_thread::get_id() << " i = " << i << endl;
}
mythread.join();
}
三用lambda表达式
[](){}
//运行结果为:
//Hello World0 start!
//mylambdathread start...Hello World1 end!
//Hello World2 end!
//Hello World3 end!
//Hello World4 end!
//
//mylambdathread end...
//Hello World5 end!
//Hello World6 end!
void main() {
std::cout << "Hello World0 start!\n";
auto mylambdathread = []() {
cout << "mylambdathread start..." << endl;
cout << "mylambdathread end..." << endl;
};
thread mythread(mylambdathread);
std::cout << "Hello World1 end!\n";
std::cout << "Hello World2 end!\n";
std::cout << "Hello World3 end!\n";
std::cout << "Hello World4 end!\n";
mythread.join();
std::cout << "Hello World5 end!\n";
std::cout << "Hello World6 end!\n";
}