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

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

相关推荐
计算机安禾9 分钟前
【Linux从入门到精通】第25篇:循环结构——重复造轮子的终结者
linux·运维·chrome
vortex511 分钟前
守护开源世界的猎犬:ClamAV 软件包介绍
linux·网络安全
zzzyyy53811 分钟前
基础IO(1)
linux·运维·数据库
zzzb12345613 分钟前
WSL(Ubuntu)部署Nginx\+PHP8\.2完整教程(新手友好\+避坑指南)
linux·nginx·ubuntu·php
想拿大厂offer27 分钟前
【Linux】编辑器、IDE 与操作系统:Linux 开发工具链的哲学与实践
linux·ide·编辑器
面向对象World38 分钟前
养虾从入门到放弃(Windows&Ubuntu)
linux·运维·ubuntu
Danileaf_Guo40 分钟前
Ubuntu 26.04桌面版部署
linux·运维·服务器·ubuntu
阿洛学长44 分钟前
OpenClaw零成本部署指南:Windows/Mac/Linux/阿里云搭建+两个免费大模型API配置攻略
linux·windows·macos
IMPYLH1 小时前
Linux 的 sync 命令
linux·运维·服务器·python·bash·运维开发
handler011 小时前
【Linux 笔记】GDB 调试速查手册
linux·运维·c语言·c++·笔记