【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;
}

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

相关推荐
HLC++16 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室18 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy20 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕21 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫1 天前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生1 天前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.111 天前
linux基础IO
linux·运维·服务器
BelongPanda1 天前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯1 天前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_777998341 天前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器