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

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

相关推荐
仍然探索未知中2 小时前
【Linux内核源码分析】内核数据结构
linux·数据结构
chxii2 小时前
linux 下用 acme.sh 搞定 Nginx 免费 SSL 证书自动续期(下) 对于acme.sh命令安装详解
linux·运维·服务器
Bert.Cai2 小时前
Linux more命令详解
linux·运维
minji...2 小时前
Linux 多线程(四)线程等待,线程分离,线程管理,C++多线程,pthread库
linux·运维·开发语言·网络·c++·算法
ZGUIZ2 小时前
Ubuntu 25.10 无法外接显示器解决方案
linux·运维·ubuntu
QJtDK1R5a2 小时前
V4L2 vs GStreamer vs FFmpeg:Linux多媒体处理的三个层级
linux·运维·ffmpeg
倔强的石头1062 小时前
【Linux指南】基础IO系列(四):文件描述符 fd——Linux 文件操作的 “万能钥匙”
linux·运维·服务器
wzb562 小时前
把 Vim 打造成 Nginx 开发 / 调试 IDE(WSL Ubuntu 完整教程)
linux·ide·nginx·ubuntu·vim·c/c++
SPC的存折2 小时前
12、Ansible安全加固
linux·运维·服务器·安全·ansible