#include<iostream> #include<thread> using namespace std; //自己创建的线程也要从一个函数(初始函数)开始执行 void myprint(){ cout << "我的线程开始了1111" << endl; cout << "我的线程执行完毕了1111" << endl; cout << "我的线程开始了2222" << endl; cout << "我的线程执行完毕了2222" << endl; cout << "我的线程开始了3333" << endl; cout << "我的线程执行完毕了3333" << endl; cout << "我的线程开始了4444" << endl; cout << "我的线程执行完毕了4444" << endl; } class TA { public: int& m_i; TA(int& i) :m_i(i) { cout << "TA()的构造函数执行" << endl; } TA(const TA& ta) :m_i(ta.m_i){ cout << "TA()的拷贝构造函数执行" << endl; } ~TA() { cout << "TA()的析构函数执行" << endl;
} void operator()()//不能带参数 { cout << m_i << endl;//会产生不可预料的结果,主线程执行完后悔释放myi这个时候如果用myi变量,就会出问题,如果值传递就没关系,相当于拷贝过来的两份内存。 cout << "我的1111类线程开始了" << endl; cout << "我的1111类线程结束了" << endl; cout << "我的2222类线程开始了" << endl; cout << "我的2222类线程结束了" << endl; cout << "我的3333类线程开始了" << endl; cout << "我的3333类线程结束了" << endl; cout << "我的4444类线程开始了" << endl; cout << "我的4444类线程结束了" << endl; } }; int main() { /* (1)范例演示线程运行的开始和结束 * 程序运行起来,生成一个进程,该进程所属的主线程开始自动执行。 (1.1)thread (1.2)join() (1.3)detach() (1.4)joinable() (2)其他创建线程的手法 (2.1)用类,以及一个问题范例 (2.2)用lambda表达式 */ //cout << "I love china" << endl;//实际上是主线程在执行,从main到返回,则整个进程执行完毕
//主线程从main函数开始执行,我们自己创建的线程,也需要从一个函数开始执行(初始函数),一旦这个函数运行完毕,则代表着这个线程运行结束。 //整个进程是否执行完毕的标志是主线程是否执行,如果主线程执行完毕了,就代表整个进程执行完毕。 //此时,一般情况下:如果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止。 //所以,一般情况下,如果大家想保持子线程的运行状态,那么就要让主线程(用代码创建的线程)一直爆出运行,不能让其运行完毕。 //这条规律有意外,后续会解释,目前先这么理解
//a)包含一个头文件thread //b)初始函数要写 //c)main中开始写代码 //必须明确一点:有两个线程在跑,相当整个程序的 执行有两条线在同时走,所以,可以同时做两个事情。即使一条线被堵住了,另外一条线还是可以通行。这就是多线程 //(1.1)thread:是个标准库里的类 //(1.2)join():加入汇合,说白了就是阻塞,阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合, 然后主线程再往下走。 //如果主线程执行完毕了,但子线程没执行完毕,这种程序是不合格的,也是不稳定的 //一个书写良好的程序,应该是主线程等待子线程执行完毕后,自己才能最终退出。 //(1.3)detach():传统多线程程序在主线程要等待子线程执行完毕,然后自己再最后退出。 //datach:分离 主线程不和子线程汇合了,你主线程执行你的,我子线程执行我的,你主线程也不必等我子线程运行结束,你可以先执行结束,这并不影响子线程的执行。 //为什么引入detach():我们创建了很多子线程,让主线程逐个等待子线程结束,这种编程方法不太好,所以引入了detach(); //一旦detach()之后,与这个主线程关联的thread对象就会失去与这个主线程的关联,此时这个子线程就会驻留在后台运行了(主线程与该子线程失去联系)。 //这个子线程就相当于被C++运行时库接管,当这个子线程执行完成后,由运行时库负责清理该线程相关的资源(守护线程)。 //detach()使线程myprint失去我们自己的控制。 //(1.4)joinable()判断是否可以成功使用join()或者detach()的,返回true或者false //
//myprint是一个可调用对象 std::thread mytobj(myprint);//(1)创建了线程,线程执行起点(入口)myprint(); (2)myprint()线程开始执行 //阻塞主线程并等待myprint子线程执行完。 /*mytobj.join();*///主线程阻塞到这里等待myprint()执行完。当子线程执行完毕。这个join()就执行完毕,主线程就开始继续执行 mytobj.detach();//一旦调用detach()就不能再join回来了,不能再用join(),否则系统会报告异常 if (mytobj.joinable()) { cout << "可以使用join或者detach" << endl; } else { cout << "不能使用join或者detach" << endl; } cout << "主线程收尾,最终主线程安全退出1" << endl; cout << "主线程收尾,最终主线程安全退出2" << endl; cout << "主线程收尾,最终主线程安全退出3" << endl; cout << "主线程收尾,最终主线程安全退出4" << endl; cout << "主线程收尾,最终主线程安全退出5" << endl;
/*二:其他创建线程的手法 (2.1)用类,以及问题范例 问题:一旦调用了detach(),那我主线程执行结束了,我这里用的这个ta对象还在吗?(对象不在了) 答案:这个对象实际上是被赋值到线程中去;所以执行完主线程后,ta会被销毁,但是所赋值的ta对象依旧存在 所以,只要这个TA类对象里面没有引用,没有指针,那么就不会产生问题。 */ int myi = 6; TA ta(myi); thread mytobj3(ta); mytobj3.detach();
//(2.2)用lambda表达式创建 auto mylamthread = [] { cout << "我的线程3开始执行了" << endl;
cout << "我的线程3执行结束了了" << endl; }; thread mytobj4(mylamthread); mytobj4.join();
cout << "I LOVE CHINA" << endl; cout << "I LOVE CHINA" << endl; cout << "I LOVE CHINA" << endl; cout << "I LOVE CHINA" << endl; cout << "I LOVE CHINA" << endl; return 0;
}