C/C++教程

std::get<C++11多线程库>(02): 如何启动一个线程

本文主要是介绍std::get<C++11多线程库>(02): 如何启动一个线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
  1 #include <QCoreApplication>
  2 #include <iostream>
  3 #include <thread>  //管理线程的类和函数
  4 
  5 /*
  6  * 话题1: 如何启动
  7  *
  8  * 在使用C++线程标准库时,
  9  * C++如何启动一个线程, 变为了如何构造一个 std::thread 对象。
 10  *
 11  * 构造 std::thread 有以下几种:
 12  * 1. 传入一个函数作为参数
 13  * 2. 传入一个可调用对象
 14  * 3. 传入一个 lamdba 对象
 15 */
 16 
 17 /*
 18  * 思考:对于一个线程, 如何给线程传入参数, 如何从线程得到返回值
 19 */
 20 
 21 
 22 /*
 23  * 话题2:启动线程之后,就需要明确是等待线程的执行(加入式),还是让其自行运行(分离式)。
 24  *
 25  * 如果std::thread对象销毁之前还没有做出决定,新线程就会终止。需要确保线程能够正确的加入(joined)或分离(detached)。
 26  * 因此,如果未明确新线程的执行方式,则可能导致新线程运行不完整。
 27  *
 28  * std::thread 的析构函数会调用 std::terminate() 终止新线程的运行。
 29  *
 30 */
 31 
 32 void way_one(){//话题1
 33     std::cout<<"way_one  hello word"<<std::endl;
 34 }
 35 
 36 class way_two//话题1
 37 {
 38 public:
 39     way_two(){}
 40     void operator()(){
 41         std::cout<<"way_two  hello word"<<std::endl;
 42     }
 43 };
 44 
 45 void way_threed(){//话题1
 46     std::cout<<"way_threed  hello word"<<std::endl;
 47 }
 48 
 49 void way_four(){//话题2
 50     std::cout<<"way_four  hello word"<<std::endl;
 51 }
 52 
 53 
 54 //int main(int argc, char *argv[])
 55 //{
 56 //    QCoreApplication a(argc, argv);
 57 
 58 //    std::thread t_one(way_one);
 59 //    t_one.join();
 60 
 61 //    way_two _way_two;
 62 //    std::thread t_two(_way_two);  //函数对象 _way_two 会复制到新线程的内存空间中, 函数对象的调用和执行都在新线程的内存空间中。
 63 //                                  //函数对象的副本应与原始函数对象保持一致,否则得到的结果会与我们的期望不同。
 64 //    t_two.join();
 65 
 66 ////    std::thread _way_two_1(way_two()); //编程了定义一个函数  std::thread  func ( param );
 67 //                                         //有件事需要注意,当把函数对象传入到线程构造函数中时,需要避免“最令人头痛的语法解析”(C++’s most vexing parse,
 68 //                                         //中文简介)。如果你传递了一个临时变量,而不是一个命名的变量;C++编译器会将其解析为函数声明,而不是类型对象的定义。
 69 
 70 //    std::thread _way_two_2((way_two()));  //解决办法1: 给临时对象添加一对儿括号
 71 //    _way_two_2.join();
 72 
 73 //    std::thread _way_two_3{way_two()};    //解决方法2: 采用 大括号的初始化语义
 74 //    _way_two_3.join();
 75 
 76 //    std::thread _way_three([]{
 77 //        way_threed();
 78 //    });
 79 //    _way_three.join();
 80 
 81 //    std::thread _way_four(way_four); //可能会执行到,也可能执行不到,看运气
 82 //                                     //main()函数执行结束, _way_four 对象会被析构, std::thread 析构会调用 std::terminate() 终止新线程。
 83 //    return a.exec();
 84 //}
 85 
 86 /*
 87  * join 函数: 初始线程等待新县城执行完毕再继续往下执行。
 88  *
 89  * 把上面的所有join的调用放到 main() 函数的 return a.exec() 的上方,再来看看。
 90  *
 91  * 2.1.2 等待线程完成
 92  *       每创建一个 std::thread 对象,就紧接着使用 join(),因此原始线程在其生命周期中并没有做什么事,
 93  *       使得用一个独立的线程去执行函数变得收益甚微,
 94  *       但在实际编程中,原始线程要么有自己的工作要做;要么会启动多个子线程来做一些有用的工作,并等待这些线程结束。
 95  *       所以说,上面的 main()函数的流程,很明显不恰当,应当像下面的 main() 一样,在最后使用 join(),
 96  *       在类中使用 std::thread 可以在对应的析构函数中使用 join()。
 97  *
 98  * join()是简单粗暴的等待线程完成或不等待。
 99  * 当你需要对等待中的线程有更灵活的控制时,比如,看一下某个线程是否结束,
100  * 或者只等待一段时间(超过时间就判定为超时)。想要做到这些,你需要使用其他机制来完成,比如条件变量和期待(futures)
101  *
102  *
103  * 调用join()的行为,还清理了线程相关的存储部分,这样std::thread对象将不再与已经完成的线程有任何关联。
104  * 这意味着,只能对一个线程使用一次join();一旦已经使用过join(),std::thread对象就不能再次加入了,
105  * 当对其使用joinable()时,将返回false。
106 */
107 int main(int argc, char *argv[])
108 {
109     QCoreApplication a(argc, argv);
110 
111     std::thread t_one(way_one);
112 
113     way_two _way_two;
114     std::thread t_two(_way_two);  //函数对象 _way_two 会复制到新线程的内存空间中, 函数对象的调用和执行都在新线程的内存空间中。
115                                   //函数对象的副本应与原始函数对象保持一致,否则得到的结果会与我们的期望不同。
116 
117 //    std::thread _way_two_1(way_two()); //编程了定义一个函数  std::thread  func ( param );
118                                          //有件事需要注意,当把函数对象传入到线程构造函数中时,需要避免“最令人头痛的语法解析”(C++’s most vexing parse,
119                                          //中文简介)。如果你传递了一个临时变量,而不是一个命名的变量;C++编译器会将其解析为函数声明,而不是类型对象的定义。
120 
121     std::thread _way_two_2((way_two()));  //解决办法1: 给临时对象添加一对儿括号
122 
123     std::thread _way_two_3{way_two()};    //解决方法2: 采用 大括号的初始化语义
124 
125     std::thread _way_three([]{
126         way_threed();
127     });
128 
129 
130     t_one.join();
131     t_two.join();
132     _way_two_2.join();
133     _way_two_3.join();
134     _way_three.join();
135     return a.exec();
136 }

 

这篇关于std::get<C++11多线程库>(02): 如何启动一个线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!