【Linux跬步积累】——thread封装

🌏博客主页:PH_modest的博客主页

🚩当前专栏:Linux跬步积累

💌其他专栏:

🔴 每日一题

🟡 C++跬步积累

🟢 C语言跬步积累

🌈座右铭:广积粮,缓称王!

文章目录


创建文件

首先创建一个.hpp文件和一个.cc文件,.hpp文件内进行对thread的封装,然后在.cc文件下进行测试。

提示:.hpp文件是类似于.h文件,更多用于C++中,用于和C语言的进行区分,.hpp文件内包含类、模版、函数、宏的定义和声明,它允许在多个源文件中共享代码,避免重复编写。

.hpp文件的创建、thread类的函数定义

cpp 复制代码
#ifndef __THREAD_HPP__ //避免头文件重复包含
#define __THREAD_HPP__

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

//命名空间
namespace ThreadModule
{
    template<class T>
    using func_t = std::function<void(T&)>;//模版方法,下面参数的定义也要带模版

    template<class T>
    class Thread
    {
    public:
        Thread(func_t<T> func,const T &data,const std::string &name="none_name")
            :_func(func),_data(data),_threadname(name),_stop(true)
        {}
        bool Start()//启动并创建线程
        {}
        void Detach()//分离线程
        {}
        void Join()//等待线程
        {}
        void Stop()//终止线程
        {}
        ~Thread()
        {}
    private:
        pthread_t _tid;
        std::string _threadname;
        T _data;
        func_t<T> _func;
        bool _stop;
    };

}//namespace ThreadModule
#endif

.cc文件的创建

cpp 复制代码
#include "Thread.hpp"
#include <iostream>
#include<vector>

using namespace ThreadModule;

const int num=10;

int main()
{
    //1.创建一批线程
    
    //2.启动一批线程
    
    //3.等待一批线程
    
    return 0;
}

.hpp内thread类基础函数的实现

cpp 复制代码
#ifndef __THREAD_HPP__
#define __THREAD_HPP__

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

//命名空间
namespace ThreadModule
{
    template<class T>
    using func_t = std::function<void(T&)>;//模版方法,下面参数的定义也要带模版

    template<class T>
    class Thread
    {
    public:
        void Excute()
        {
            _func(_data);
        }
    public:
        Thread(func_t<T> func,const T &data,const std::string &name="none_name")
            :_func(func),_data(data),_threadname(name),_stop(true)
        {}

        static void* Threadroutinue(void* args)//类成员函数,形参是有this指针的!!!,不满足pthread_create的传参要求。所以需要加static
        {
            Thread<T>* self=static_cast<Thread<T>*>(args);
            self->Excute();
            return nullptr;
            
            //会报错,因为访问成员函数前需要加this指针,但是static没有this指针
            //_func(_data);

            //测试代码
            // while(true)
            // {
            //     std::cout<<"I am new thread..."<<std::endl;
            //     sleep(1);
            // }
        }
        
        bool Start()
        {
            int n = pthread_create(&_tid,nullptr,Threadroutinue,this);
            if(!n)
            {
                _stop=false;
                return true;
            }
            else
            {
                return false;
            }
        }
        void Detach()
        {
            if(!_stop)
                pthread_detach(_tid);
        }
        void Join()
        {
            if(!_stop)
                pthread_join(_tid,nullptr);
        }
        void Stop()
        {
            _stop=true;
        }
        std::string name()
        {
            return _threadname;
        }
        ~Thread()
        {}
    private:
        pthread_t _tid;
        std::string _threadname;
        T _data;
        func_t<T> _func;
        bool _stop;
    };

}//namespace ThreadModule

#endif

知识点1:

其他函数的实现只需要调用pthread库就可以了,但是我们使用pthread_create()函数来调用成员函数Threadroutinue()时,如果Threadroutinue()前面不加static则会报错,因为pthread_create()第三个参数是一个返回值为void*,参数为void*的一个函数,而成员函数会隐藏一个this指针,这就会导致出错,因此我们只需要加上static,那么成员函数就不会带有this指针了。

但是当我们想用成员函数Threadroutinue()调用成员变量_func,来使用外部传递的函数时,因为没有this指针,导致我们无法调用,这又应该如何解决呢?

于是我们可以再定义一个函数Excute(),我们使用Excute()来调用_func,然后pthread_create()函数的第四个参数传递this指针,这样Threadroutinue()就可以用传递的this指针调用Excute()函数了,这样就可以完美解决问题。

知识点2:

我们可以使用#include<functional>头文件内的function函数来定义一个函数指针,类似于文中的std::function<void(T&)>,这里的void表示函数的返回值,T&表示函数的参数 。因此我们之后就可以传递void Printf(int &data)函数给线程了。

.cc内thread类的简单调用

cpp 复制代码
#include "Thread.hpp"
#include <iostream>
#include<vector>

using namespace ThreadModule;

void Printf(int &data)
{
    while(data)
    {
        std::cout<<"hello I am myself thread,data:"<<data--<<std::endl;
        sleep(1);
    }
}


const int num=10;

int main()
{
    std::vector<Thread<int>> threads;
    //1.创建一批线程
    for(int i=0;i<num;i++)
    {
        std::string name = "thread-"+std::to_string(i+1);
        threads.emplace_back(Printf,10,name);
    }
    //2.启动一批线程
    for(auto &thread:threads)
    {
        thread.Start();
    }
    //3.等待一批线程
    for(auto &thread:threads)
    {
        thread.Join();
        std::cout<<"wait thread done...thread is"<<thread.name()<<std::endl;
    }
    return 0;
}

运行演示

总结

本篇博客没有过多讲解代码,这里是默认大家都能看懂的,主要是为了讲解一下文中的两个知识点,如果对代码部分有疑问可以看看我的前几篇有关线程的博客。

相关推荐
蓁蓁啊2 小时前
GIT使用SSH 多账户配置
运维·git·ssh
路由侠内网穿透4 小时前
本地部署开源持续集成和持续部署系统 Woodpecker CI 并实现外部访问
服务器·网络·windows·ci/cd·开源
程序猿小三4 小时前
Linux下基于关键词文件搜索
linux·运维·服务器
虚拟指尖5 小时前
Ubuntu编译安装COLMAP【实测编译成功】
linux·运维·ubuntu
椎4956 小时前
苍穹外卖前端nginx错误之一解决
运维·前端·nginx
刘某的Cloud6 小时前
parted磁盘管理
linux·运维·系统·parted
啊?啊?6 小时前
4 解锁 Linux 操作新姿势:man、grep、tar ,创建用户及添加权限等 10 大实用命令详解
linux·服务器·实用指令
程序员老舅6 小时前
干货|腾讯 Linux C/C++ 后端开发岗面试
linux·c语言·c++·编程·大厂面试题
极验6 小时前
iPhone17实体卡槽消失?eSIM 普及下的安全挑战与应对
大数据·运维·安全
爱倒腾的老唐6 小时前
24、Linux 路由管理
linux·运维·网络