【Linux】线程概念与控制(4)_线程封装

hello~ 很高兴见到大家! 这次带来的是Linux系统中关于线程这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页 : 默|笙


文章目录


一、代码实现

  1. 下面是 thread.hpp 文件代码,是对 一些 pthread 函数的封装操作:
cpp 复制代码
#pragma once

#include <pthread.h>
#include <functional>
#include <iostream>

namespace ThreadMoudle
{
    int gnumber = 1;
    using callback_t = std::function<void()>;
    enum class TSTATUS
    {
        THREAD_NEW,
        THREAD_RUNNING,
        THREAD_STOP
    };

    std::string IsJoined(bool joinable)
    {
        return joinable ? "Joinable" : "Detached";
    }
    std::string Status2String(TSTATUS s)
    {
        switch (s)
        {
        case TSTATUS::THREAD_NEW:
            return "THREAD_NEW";
        case TSTATUS::THREAD_RUNNING:
            return "THREAD_RUNNING";
        case TSTATUS::THREAD_STOP:
            return "THREAD_STOP";
        default:
            return "UNKNOWN";
        }
    }
    class Thread
    {
    private:
        void ToRunning()
        {
            _status = TSTATUS::THREAD_RUNNING;
        }
        void ToStop()
        {
            _status = TSTATUS::THREAD_STOP;
        }
        //线程要执行的函数,必须加上static,不加第一个参数会是this指针
        static void *Routine(void *args)
        {
            Thread *it = static_cast<Thread*>(args);
            //线程要执行的任务   
            it->_ct();
            pthread_setname_np(it->_tid, it->_name.c_str());
            it->ToStop();

            return nullptr;
        }

    public:
        Thread(callback_t ct)
            : _tid(-1), _status(TSTATUS::THREAD_NEW), _ct(ct), _joinable(true), _result(nullptr)
        {
            _name = "New-Thread-" + std::to_string(gnumber++);
        }
        bool Start()
        {
            //把this传递给要执行的函数
            int n = pthread_create(&_tid, nullptr, Routine, this);
            ToRunning();

            if (n != 0)
                return false;
            return true;
        }
        void Join()
        {
            if (_joinable)
            {
                int n = pthread_join(_tid, &_result);
                if (n != 0)
                {
                    std::cerr << "join error:" << n << std::endl;
                    return;
                }
                (void)_result;
                ToStop();
            }
            else
            {
                std::cerr << "join error, joinable: " << IsJoined(_joinable) << std::endl;
            }
        }
        void Die()
        {
            if (_status == TSTATUS::THREAD_RUNNING)
            {
                pthread_cancel(_tid);
                ToStop();
            }
        }
        void Detach()
        {
            if (_joinable)
            {
                pthread_detach(_tid);
                _joinable = false;
            }
            else
            {
                std::cerr << "detach " << _name << "failed" << std::endl;
            }
        }
        ~Thread()
        {
        }
        void Print()
        {
            std::cout << "_name: " << _name << std::endl;
            std::cout << "tid: " << _tid << std::endl;
            std::cout << "status: " << Status2String(_status) << std::endl;
            std::cout << "joinable: " << IsJoined(_joinable) << std::endl;
        }

    private:
        std::string _name;//线程名字
        pthread_t _tid;//线程id
        TSTATUS _status;//线程的执行状态

        callback_t _ct;//线程要执行的任务
        bool _joinable;//线程是否可以被等待
        void* _result;//线程的返回值
    };
}
  1. 之所以 Routine 函数必须声明为静态(加上 static),是因为如果不加 static,它就属于类的非静态成员函数,会隐式携带 this 指针作为第一个参数,导致函数签名与 pthread_create 要求的线程入口函数格式不匹配。pthread_create 要求线程入口函数必须是无 this 指针、参数为单个 void*、返回值为 void* 的普通函数指针格式。而我们后续访问类的非静态私有成员时又必须用到 this 指针,因此在调用 pthread_create 时,就把当前对象的 this 指针以 void* 类型作为参数传递给这个静态 Routine 函数,再在函数内部还原出对象指针,从而正常访问类成员

二、解决传参问题

1.1 使用模板

  1. 可以使用模板来解决传参问题,下面是使用单个模板参数解决传递单参数的方法,如果要传递多参数可以使用可变参数模板。要修改 thread.hpp 文件。
cpp 复制代码
#pragma once

#include <pthread.h>
#include <functional>
#include <iostream>

namespace ThreadMoudle
{
    int gnumber = 1;
    template<typename T>
    using callback_t = std::function<void(T&)>;
    enum class TSTATUS
    {
        THREAD_NEW,
        THREAD_RUNNING,
        THREAD_STOP
    };

    std::string IsJoined(bool joinable)
    {
        return joinable ? "Joinable" : "Detached";
    }
    std::string Status2String(TSTATUS s)
    {
        switch (s)
        {
        case TSTATUS::THREAD_NEW:
            return "THREAD_NEW";
        case TSTATUS::THREAD_RUNNING:
            return "THREAD_RUNNING";
        case TSTATUS::THREAD_STOP:
            return "THREAD_STOP";
        default:
            return "UNKNOWN";
        }
    }

    template<typename T>
    class Thread
    {
    private:
        void ToRunning()
        {
            _status = TSTATUS::THREAD_RUNNING;
        }
        void ToStop()
        {
            _status = TSTATUS::THREAD_STOP;
        }
        //线程要执行的函数,必须加上static,不加第一个参数会是this指针
        static void *Routine(void *args)
        {
            Thread *it = static_cast<Thread<T>*>(args);
            //线程要执行的任务   
            it->_ct(it->_data);
            pthread_setname_np(it->_tid, it->_name.c_str());
            it->ToStop();

            return nullptr;
        }

    public:
        Thread(callback_t<T> ct, const T& data)
            : _tid(-1)
            , _status(TSTATUS::THREAD_NEW)
            , _ct(ct)
            , _joinable(true)
            , _result(nullptr)
            , _data(data)
        {
            _name = "New-Thread-" + std::to_string(gnumber++);
        }
        bool Start()
        {
            //把this传递给要执行的函数
            int n = pthread_create(&_tid, nullptr, Routine, this);
            ToRunning();

            if (n != 0)
                return false;
            return true;
        }
        void Join()
        {
            if (_joinable)
            {
                int n = pthread_join(_tid, &_result);
                if (n != 0)
                {
                    std::cerr << "join error:" << n << std::endl;
                    return;
                }
                (void)_result;
                ToStop();
            }
            else
            {
                std::cerr << "join error, joinable: " << IsJoined(_joinable) << std::endl;
            }
        }
        void Die()
        {
            if (_status == TSTATUS::THREAD_RUNNING)
            {
                pthread_cancel(_tid);
                ToStop();
            }
        }
        void Detach()
        {
            if (_joinable)
            {
                pthread_detach(_tid);
                _joinable = false;
            }
            else
            {
                std::cerr << "detach " << _name << "failed" << std::endl;
            }
        }
        ~Thread()
        {
        }
        void Print()
        {
            std::cout << "_name: " << _name << std::endl;
            std::cout << "tid: " << _tid << std::endl;
            std::cout << "status: " << Status2String(_status) << std::endl;
            std::cout << "joinable: " << IsJoined(_joinable) << std::endl;
        }

    private:
        std::string _name;//线程名字
        pthread_t _tid;//线程id
        TSTATUS _status;//线程的执行状态

        callback_t<T> _ct;//线程要执行的任务
        bool _joinable;//线程是否可以被等待
        void* _result;//线程的返回值

        T _data;
    };
}

1.2 使用类和lambda表达式

  1. 我们可以把任务和它所涉及的一些变量打包成一个类,然后通过传递无参无返回值的lambda表达式(匿名函数对象)给目标线程,从而实现传递多个参数。这样就不用修改我们封装的 thread.hpp 文件了。
cpp 复制代码
#include <iostream>
#include "Thread.hpp"
#include <unistd.h>
#include <vector>

class Task
{
public:
    Task(int x, int y) : _x(x), _y(y)
    {}
    void Execute()
    {
        _result = _x + _y;
    }
    void Print()
    {
        std::cout << _x <<  " + " << _y << " = " << _result << std::endl; 
    }
    ~Task()
    {}
private:
    int _x;
    int _y;
    int _result;
};



int main()
{
    Task tk(12, 20);
    ThreadMoudle::Thread thread([&tk](){tk.Execute();});
    thread.Start();
    thread.Join();
    thread.Print();
    sleep(5);
    tk.Print();
    return 0;
}

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!

相关推荐
wj3055853788 小时前
课程 9:模型测试记录与 Prompt 策略
linux·人工智能·python·comfyui
abigriver8 小时前
打造 Linux 离线大模型级语音输入法:Whisper.cpp + 3090 显卡加速与 Rime 中英混输终极调优指南
linux·运维·whisper
wangqiaowq9 小时前
windows下nginx的安装
linux·服务器·前端
YYRAN_ZZU9 小时前
Petalinux新建自动脚本启动
linux
charlie11451419110 小时前
嵌入式Linux驱动开发pinctrl篇(1)——从寄存器到子系统:驱动演进之路
linux·运维·驱动开发
于小猿Sup10 小时前
VMware在Ubuntu22.04驱动Livox Mid360s
linux·c++·嵌入式硬件·自动驾驶
cen__y10 小时前
Linux12(Git01)
linux·运维·服务器·c语言·开发语言·git
不仙52012 小时前
VMware Workstation 26.0.0 在 Ubuntu 24.04 (内核 6.17.0) 上的安装与内核模块编译问题
linux·ubuntu·elasticsearch
AI视觉网奇12 小时前
linux 检索库 判断库是否支持
java·linux·服务器
dapeng-大鹏12 小时前
KVM+LVM 零停机在线扩容 Ubuntu 根分区:从磁盘添加到逻辑卷扩展完整
linux·运维·ubuntu·磁盘空间扩展