• 【Linux】23. 线程封装


    如何理解C++11中的多线程(了解)

    #include 
    #include 
    #include 
    
    void thread_run()
    {
        while (true)
        {
            std::cout << "我是新线程..." << std::endl;
            sleep(1);
        }
    }
    int main()
    {
        // 任何语言需要在Linux上实现多线程,必定是要用到pthread库的!
        // 如何看待C++11中的多线程呢?
        // 本质上就是对pthread库的封装
        std::thread t1(thread_run);
    
        while (true)
        {
            std::cout << "我是主线程..." << std::endl;
            sleep(1);
        }
    
        t1.join();
    
        return 0;
    }
    

    在这里插入图片描述

    封装代码

    封装代码写在Thread.hpp 文件当中,未来想使用封装好的线程就直接包含Thread.hpp文件即可!

    // hpp 表示header only 开源代码
    // 将函数定义和声明放在一起
    
    #pragma once
    
    #include 
    #include 
    #include 
    #include 
    #include 
    
    // 先声明 要使用
    class Thread;
    
    // 上下文,当大号结构体使用
    // 用Context来处理静态方法调用不了成员变量的问题
    class Context
    {
    public:
        Thread *this_;
        void *args_;
    
    public:
        Context() : this_(nullptr), args_(nullptr)
        {}
        ~Context()
        {}
    };
    
    // 对线程做封装,以后就不需要总去调用原生库的接口了
    class Thread
    {
    public:
        // using func_t = std::function; -- C++11 智能指针
        typedef std::function<void *(void *)> func_t;
        const int num = 1024;
    
        // "void *(Thread::*)(void *args)" 类型的实参与 "void *(*)(void *)" 类型的形参不兼容C/C++(167) -- 报错
        // 为啥呢? -- 因为start_routine是类内的成员函数,有缺省参数this指针
        // void* start_routine(void* args)
        // {
        //     return func_(args);
        // }
    
        // 在类内创建线程  这样就没有this指针了
        static void *start_routine(void *args)
        {
            // 但是没有this指针
            // 静态方法不能调用成员方法或成员变量
            // return func_(args);
            // 可以采用友元,或者public成员的方式 这里不用!!
            
            // 将args强转成Context的指针
            Context *ctx = static_cast<Context*>(args);
            // 调用run方法 -- 将方法从静态中剥离出来
            void* ret = ctx->this_->run(ctx->args_);
            delete ctx;
            return ret;
        }
    
        // 构造函数
        Thread(func_t func, void *args = nullptr, int number = 0) : func_(func), args_(args)
        {
            char buffer[num];
            snprintf(buffer, sizeof buffer, "thread-%d", number);
            name_ = buffer;
    
            // 加上Context
            Context* ctx = new Context();
            ctx->this_ = this;
            ctx->args_ = args_;
            // 将ctx传过去
            int n = pthread_create(&tid_, nullptr, start_routine, ctx);
            //int n = pthread_create(&tid_, nullptr, start_routine, args);
            assert(n == 0);
            (void)n;
        }
    
        // 线程等待
        void join()
        {
            int n = pthread_join(tid_, nullptr);
            assert(n == 0);
            (void)n;
        }
    
        void *run(void *args)
        {
            return func_(args);
        }
    
        // 析构
        ~Thread()
        {
            // do nothing
        }
    
    private:
        // 自定义线程名 方便观察(不需要通过观察tid)
        // 末尾加_ 将成员变量和参数做区分
        std::string name_;
        pthread_t tid_;
        // 线程执行任务
        func_t func_;
        // 获取参数
        void *args_;
    };
    
    

    使用封装

    #include "Thread.hpp"
    #include 
    #include 
    
    void *thread_run(void *args)
    {
        std::string work_type = static_cast<const char *>(args);
        while (true)
        {
            std::cout << "我是一个新线程,我正在做:" << work_type << std::endl;
            sleep(1);
        }
    }
    
    int main()
    {
        std::unique_ptr<Thread> thread1(new Thread(thread_run, (void *)"hellothread", 1));
        std::unique_ptr<Thread> thread2(new Thread(thread_run, (void *)"countthread", 2));
        std::unique_ptr<Thread> thread3(new Thread(thread_run, (void *)"printthread", 3));
        std::unique_ptr<Thread> thread4(new Thread(thread_run, (void *)"iothread", 4));
    
        thread1->join();
        thread2->join();
        thread3->join();
        thread4->join();
        return 0;
    }
    

    在这里插入图片描述

  • 相关阅读:
    JavaScript高阶班之ES6 → ES11(八)
    深入了解Spring Boot Actuator
    pytorch.创建神经网络
    【结构体内功修炼】结构体实现位段(二)
    测评自养号的优势和弊端有哪些?
    Swift页面添加水印
    很详细的系列Shell基础— Shell简介
    C#使用词嵌入向量与向量数据库为大语言模型(LLM)赋能长期记忆实现私域问答机器人落地
    探究竟篇之React中的state
    2022.8.29-9.4 AI行业周刊(第113期):世界人工智能大会
  • 原文地址:https://blog.csdn.net/weixin_60915103/article/details/139253875