1. 线程管理基础

线程管理的基础

  • 每个程序至少都有一个线程
  • 各自线程都有自己的入口函数
  • 其他线程和main函数线程同时运行

启动线程

  • 线程在std::thread对象创建时启动

    void do_some_work();
    std::thread my_thread(do_some_work);

  • 除了直接使用函数之外,仿函数也可以作为入口函数

    class test{
    public :
    void operator()()const{
    ...
    }
    }
    test A;
    std::thread my_thread(A)

  • 代码中提供的函数对象会复制到新线程的存储空间中,函数对象的副本和原始函数对象保持一直

  • 注意在使用仿函数作为入口的时候,如果传入临时对象会存在语法解析问题,如下

    std::thread my_thread(test())
    这个时候C++将上述语句解释为返回值为thread,参数为test对象的函数
    如果需要达到我们入口函数的目的可以参考一下写法
    std::thread my_thread((test()))
    std::thread my_thread{test()}

  • lambda表达式也可作为入口函数

    std::thread my_thread([]{...})

  • 启动线程后需要明确是等待线程结束(join())还是让线程自主运行(detach())如果在thread对象结束的时候还没有做出决定,程序就会终止

  • 如果不等待线程,就必须保证在子线程结束之前,可访问的数据一直有效,使用一个能访问局部变量的函数去创建一个线程是一个糟糕的主意

  • 需要在主线程的异常抛出之前调用join()

      struct func;
      void f(){
        int state = 0;
        func my_func(stat);
        std::thread t(my_func);
        try{
          ...;
        }
        catch(...){
          t.join();
          throw;
        }
        t.join();
      }
    
  • 为了确定主线程在结束的时候,能够保证等待使用了局部变量的子线程,可以采用如下方法:

      class thread_guard{
        std::thread & t;
        public:
          explicit thread_guard(std::thread & td):t(td){};
          ~thread_guard(){if(t.joinable()){t.join()}};
      }
      void f(){
        int tmp = 0;
        std::thread t(my_func,tmp);
        thread_guard g(t);
      }
    

    这个时候当tmp走出作用域的时候,t线程对象也会走出作用域,g的析构函数就会自动join() t对象

  • 使用detach()会让线程后台运行,这就意味这主线程不能与之产生直接交互

      void myfun();
      std::thread t(myfunc);
      t.detach()
    

参考文献

  • 本文档是我在学习C++并发编程时的笔记,参考书籍《C++并发编程》中文版

本文作者:^江流儿^

本文链接:https://www.cnblogs.com/hhyandcpp/p/17020688.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ^江流儿^  阅读(46)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.