• 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 }
  • 相关阅读:
    Python+Flask使用蓝图
    Python+selenium实现自动登录
    Python+Flask做个简单的表单提交程序
    第一个Flask程序
    PHP读取IIS网站列表
    在IIS7上导出所有应用程序池的方法 批量域名绑定
    Delphi判断一个字符串是否全是相同的数字
    WeTest六周年 | 匠心不改 初心不变
    WeTest压测大师链路性能监控 | 一站式压测、监控解决方案,开放免费体验预约
    WeTest自助压测1折起,最低1分钱参与Q币抽奖
  • 原文地址:https://www.cnblogs.com/azbane/p/15334373.html
Copyright © 2020-2023  润新知