基于linux操作系统的线程封装(可实现任意传递任意类型任意个数的参数)

一. pthread库提供的接口函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg); //创建一个线程
int pthread_join(pthread_t thread, void **retval);//线程等待
int pthread_detach(pthread_t thread);//线程分离

        其中,pthread_create为创建线程,pthread_t *thread 是一个输入输出参数,当成功创建线程后,thread为线程的tid,atrr为线程属性,一般设置为NULL,start_routine为函数指针,其传参类型为void*,arg 为待传入参数。

        当主线程程序执行完后,主线程的退出会导致整个进程退出,因此会发生其他线程未执行完任务也随着主线程退出而退出,因此可以用pthread_join和pthread_detach实现线程等待或线程分离,其中retval为输入输出参数,可以记录线程执行完后的返回值

        注意到线程创建的回调函数类型必须是void*(void*) 因此,如果我们想传多个参数时必须先定义结构体再传结构体的指针,这在书写代码时造成了一定的不便,例如如果我们希望传输一个学生(id,姓名,班级)等信息传给所创造的线程只能用如下方式:

#include<iostream>
#include<string>
#include<pthread.h>
struct student
{
    student(int id,int class_id,std::string name)
    :_id(id),_class_id(id),_name(name)
    {}
    int _id; 
    int _class_id;
    std::string _name;
};//学生结构体
void* thread_callback(void* _student) //回调函数
{
    student* st=static_cast<student*>(_student); //类型转换
    std::cout<<"name:"<<st->_name<<" id:"<<st->_id<<" class_id:"<<st->_class_id<<std::endl;
    //输出姓名,id,班级
    return nullptr;
}
int main()
{
    student st(1,1,"zzz"); //创建学生变量
    pthread_t tid; //创建tid
    pthread_create(&tid,nullptr,thread_callback,(void*)&st);//创建线程
    pthread_join(tid,nullptr);//线程等待
}

        因此,我们希望实现可以封装一个线程类,它可以实现任意个数以及任意类型的参数传递 

二. 在C++中封装线程

1. 利用lmbad表达式和可变参数模板绑定回调函数

        在C语言中,绑定回调函数只能用函数指针,而在C++11中,可以用function绑定回调函数:

#include<functional>
using func=std::function<void(int)>

        其中void(int)为函数类型 void为返回值,int为参数

        另外lmbda表达式的类型只和传参和返回类型有关,与捕获类型类型无关,例如:

#include<functional>
int main()
{
    double pi=3.1415926;
    std::function<int(int)> add=[&pi](int a){return a+pi;};
    //add的类型为int(int) 与捕获变量pi(double 类型无关)
}

        因此可以通过该特性实现绑定任意参数的回调函数:具体过程如下:

#include<iostream>
#include<functional>

class thread
{
public:
    using func=std::function<void(void)>;//用c++定义函数
    explicit thread(Fn&& func,Args&...arg)
    :_func([&arg...,func](){func(arg...);}) //利用lmbda表达式绑定传入参数和回调函数
    {
    }
private:
    func _func; //函数
};

        当调用回调函数时,直接调用_fun()即可完成回调;

2.完成线程封装

#ifndef _THREAD_HPP
#define _THREAD_HPP
#include<iostream>
#include<functional>
#include<pthread.h>
#include<cstdio>
#include<error.h>
#include<cstring>
namespace zwr
{
   
    class thread
    {
    public:
        using func=std::function<void(void)>;//用c++定义函数
        //typedef void*(*func)(void*); //用C语言定义函数
        template<class Fn,class... Args>
        explicit thread(Fn&& func,Args&...arg)
        :_func([&arg...,func](){func(arg...);}) 
        //利用lmbda表达式绑定传入参数和回调函数(禁止隐式类型转换)
        {
            if(!pthread_create(&(_tid),nullptr,func_c,\
            static_cast<void*>(this)))
            {
                std::cerr<<errno<<strerror(errno)<<std::endl;
            }
            //创建线程
        }
        template<class Fn,class... Args>
        explicit thread(Fn&& func,Args&&...arg)
        :_func([arg...,func](){func(arg...);})
        //利用lmbda表达式绑定传入参数和回调函数(禁止隐式类型转换)
        {
            if(pthread_create(&(_tid),nullptr,func_c,\
            static_cast<void*>(this)))//创建线程
            {
                std::cerr<<errno<<strerror(errno)<<std::endl;
            }
        }
        ~thread()
        {
        }
        bool detach() //线程分离
        {
            return !pthread_detach(_tid);
        }
        void join() //线程等待
        {
            pthread_join(_tid,nullptr);
            _tid=0;
        }
    private:
        static void* func_c(void* pth_args) //线程回调函数
        {
            thread* _thread_this=static_cast<thread*> (pth_args);
            _thread_this->_func();
            return nullptr;
        }
    private:
        func _func; //函数
        pthread_t _tid; //线程id
    };
}

#endif

3.测试

#include<iostream>
#include<string>
#include"thread.hpp"
using namespace zwr;
void thread_callback(int id,int class_id,std::string name)  //回调函数
{
    std::cout<<"name:"<<name<<" id:"<<id<<" class_id:"<<class_id<<std::endl;
    //输出姓名,id,班级
}
int main()
{
    thread t(thread_callback,1,1,"zzz");//创建线程并传参
    t.join();//线程等待
}

输出结果:

[zwr@hecsx-e774 thread2.0]$ ./thread_test 
name:zzz id:1 class_id:1

封装后的线程大大简化了代码

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值