• c++多线程学习01 对象生命周期和线程的退出与等待


    子线程:

    void ThreadMain()
    {
        cout << "begin sub thread main " << this_thread::get_id() << endl;
        for (int i = 0; i < 10; i++)
        {
            if (!is_exit) break;
            cout << "in thread " << i << endl;
            this_thread::sleep_for(chrono::seconds(1));//1000ms
        }
        cout << "end sub thread main " << this_thread::get_id() << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    main函数三种情况:
    01:

    int main(int argc, char* argv[])
    {
    {
    thread th(ThreadMain);
    }
    getchar();
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
            using _Tuple                 = tuple<decay_t<_Fn>, decay_t<_Args>...>;
            auto _Decay_copied           = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
            constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{});
    
    #pragma warning(push)
    #pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to
                                    // extern C function under -EHc. Undefined behavior may occur
                                    // if this function throws an exception. (/Wall)
            _Thr._Hnd =
                reinterpret_cast<void*>(_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));
    #pragma warning(pop)
    
            if (_Thr._Hnd) { // ownership transferred to the thread
                (void) _Decay_copied.release();
            } else { // failed to start thread
                _Thr._Id = 0;
                _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这是因为在使用函数指针做为thread的构造函数的参数时,会生成一个句柄 _Thr._Hnd ,这个句柄的生命周期与主线程一致,当主线程结束时该句柄也会被释放掉,由于此时子线程还在运行,因此将会出错

    02

    int main(int argc, char* argv[])
    {
    {
    thread th(ThreadMain);
    th.detach(); }
      getchar();
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    用detach()使子线程与主线程分离,相当于将子线程变成一个守护线程,将其资源如句柄的生命周期交给子线程
    java的守护线程:
    守护线程,是指在程序运行时 在后台提供一种通用服务的线程,这种线程并不属于程序中不可或缺的部分。通俗点讲,任何一个守护线程都是整个JVM中所有非守护线程的"保姆"。

    用户线程和守护线程几乎一样,唯一的不同之处在于如果用户线程已经全部退出运行,只剩下守护线程存在了,JVM也就退出了。因为当所有非守护线程结束时,没有了被守护者,守护线程也就没有工作可做,当然也就没有继续执行的必要了,程序就会终止,同时会杀死所有的"守护线程",也就是说只要有任何非守护线程还在运行,程序就不会终止

    在这里插入图片描述

    03

    int main(int argc, char* argv[])
    {
    {
            thread th(ThreadMain);
            th.detach(); //子线程与主线程分离 守护线程
            //坑 :主线程退出后 子线程不一定退出,因此要注意子线程不要使用主线程中的变量
        }
      {thread th(ThreadMain);
            this_thread::sleep_for(chrono::seconds(1));//模拟业务1000ms
            is_exit = true; //通知子线程退出
            cout << "主线程阻塞,等待子线程退出" << endl;
            th.join(); 
            //为了提高运行效率,在主线程业务逻辑处理结束才阻塞主线程,而不是子线程一加进来就阻塞主线程
            cout << "子线程已经退出!" << endl;}
      getchar();
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    th.join()方法用于把子线程加入到主线程中,把主线程的CPU执行时间让子线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。在加入前CPU给两个线程都分的有时间片(线程是CPU调度的基本单位),再加入后这两个线程平分原本主线程的时间片。在std::thread t(func)后“某个”合适的地方调用,其作用是回收对应创建的线程的资源,避免造成资源的泄露。

    用this_thread::sleep_for(chrono::seconds(1));来模拟业务1000ms,当主线程业务结束时需要使用is_exit = true;通知子线程结束,但由于时间片调度子线程不会一瞬间就结束,要使用th.join()来等待子线程结束,不然它的句柄被主线程释放了的话会出现问题。

    在这里插入图片描述
    可以看到创建了两个线程,由于并发的执行被显示在同一行了,
    此外可以看到子线程中的in thread 0只显示了一行,与主线程业务逻辑运行时间吻合。

  • 相关阅读:
    并查集介绍 & 代码实现 & 优化思路详解
    开源框架中的责任链模式实践
    全链路压测基础
    【redis进阶】Redis String数据类型为什么不好用
    《吐血整理》高级系列教程-吃透Fiddler抓包教程(30)-Fiddler如何抓取Android7.0以上的Https包-番外篇
    windows系统一键开启和关闭虚拟化
    455-C++ 多态(知乎)
    国产麒麟V10桌面操作系统上运行WinForm程序
    【Java】CompletableFuture学习记录
    OpenGL教程(三)
  • 原文地址:https://blog.csdn.net/qq_42567607/article/details/125457433