linux下线程的两种封装方式

来源:互联网 发布:如何网络销售水果 编辑:程序博客网 时间:2024/06/06 08:24

在网络编程的时候往往需要对Linux下原生的pthread库中的函数进行封装,使其使用起来更加方便,封装方法一般有两种:面向对象和基于对象,下面将分别介绍这两种方式,最后统一分析这两种方式的优缺点:

面向对象:

面向对象的封装方式是通过虚函数提供回调功能,我们创建一个Thread类,然后设置一个run虚函数,使用时只需要重载这个类并实现其中的虚函数即可:

具体实现如下:

//------thread.h----------------#ifndef _THREAD_H_#define _THREAD_H_#include <pthread.h>class Thread{public:    Thread();    virtual ~Thread();    void start();    void join();    void setAutoDelete(bool autoDelete);private:    static void* threadRoutine(void* args);    virtual void run() = 0;    pthread_t threadId_;    bool autoDelete_;};#endif
详细实现如下:
//---------thread.c-------------------#include "thread.h"#include <iostream>using namespace std;Thread::Thread() : autoDelete_(false){    cout << "Thread..." << endl;}Thread::~Thread(){    cout << "~Thread..." << endl;}void* Thread::threadRoutine(void* arg){    Thread* thread = static_cast<Thread*>(arg);    thread->run();    if (thread->autoDelete_)    {        delete thread;    }    return NULL;}void Thread::start(){    pthread_create(&threadId_,NULL, threadRoutine,this);}void Thread::join(){    pthread_join(threadId_, NULL);}void Thread::setAutoDelete(bool autoDelete){    autoDelete_ = autoDelete;}
View Code

调用方式如下:

#include "thread.h"#include <unistd.h>#include <iostream>using namespace std;class TestThread : public Thread{public:    TestThread(int count) : count_(count)    {        cout << "TestThread..." << endl;    }    ~TestThread()    {        cout << "~TestThread..." << endl;    }private:    void run()    {        while( count_-- )        {            cout << "This is a test" << endl;            sleep(1);        }    }private:    int count_;};int main(void){    TestThread t(5);    t.start();    t.join();    //do other work....}
View Code

  可以看到,其中有一个私有的重虚函数run,使用时只需要继承thread,实现run函数,并在其内实现线程需要执行的逻辑就可以了。

  同时有一个静态的threadRoutine成员函数,因为C++成员函数缺省的调用方式是__thiscall,成员函数中隐含的第一个参数都是this指针,所以不能匹配给pthread_create的形参void *(*start_routine) (void *), 这时候就可以传递类的一个静态成员,把this指针做为该静态成员的参数。也就是start方法的: pthread_create(&threadId_,NULL, threadRoutine,this);   在threadRoutine函数中将接收到的void*类型的参数转换成Thread*就可以了,然后调用他的run方法。

  在main函数中静态创建了一个TestThread变量 t,然后启动线程, 但是如果线程运行结束了,这个变量 t 就失去存在的价值了, 总不能一直让它在哪里占用着栈上空间吧,此时我们就可以动态创建TestThread, 然后设定其autoDelete_属性,这样当该线程执行完毕后就会检查是否需要delete掉这个堆上变量,这就是autoDelete_属性的作用,可以将main函数修改如下:

int main(void){    TestThread *t = new TestThread(5);    t->setAutoDelete(true);    t->start();    t->join();       //do other work....}
View Code

  如果你决心只在堆上分配的话,就可以将析构函数设置为私有的,这样就可以只在堆上分配,但是你还得提供一个公有的自定义的析构方法。

基于对象

  基于对象的封装方法,实现思路同上,但是它不是通过虚函数的方式实现回调的功能,而是通过函数绑定的方式, boost库中的bind/function可以实现将一个函数转换成另一种函数,就算是成员函数也可以,它相当于C++中的bind1st,bin2nd等函数适配器,在C++11中也实现了bind/function, 关于boost bind/function的使用方法,可以看这里。这里不做过多介绍。

用基于对象的封装方法如下:

//-------thread.h-------#ifndef _THREAD_H_#define _THREAD_H_#include <pthread.h>#include <boost/function.hpp>class Thread{public:    typedef boost::function<void ()> ThreadFunc;    explicit Thread(const ThreadFunc& func);    ~Thread();    void start();    void join();    void setAutoDelete(bool autoDelete);private:    static void* threadRoutine(void* args);    void run();    bool autoDelete_;    ThreadFunc func_;    pthread_t threadId_;};#endif

其中在构造函数中需要ThreadFunc对象,这个函数就是在run中调用的实例,可以看下面代码:

//---------thread.cpp-----------#include "thread.h"#include <iostream>using namespace std;Thread::Thread(const ThreadFunc& func):autoDelete_(false),func_(func){    cout << "Thread..." << endl;}Thread::~Thread(){    cout << "~Thread..." << endl;}void Thread::run(){    func_();}void* Thread::threadRoutine(void* arg){    Thread* thread = static_cast<Thread*>(arg);    thread->run();    if (thread->autoDelete_)    {        delete thread;    }    return NULL;}void Thread::start(){    pthread_create(&threadId_,NULL, threadRoutine,this);}void Thread::join(){    pthread_join(threadId_, NULL);}void Thread::setAutoDelete(bool autoDelete){    autoDelete_ = autoDelete;}
View Code

在主函数中调用方法也很简单:

#include "thread.h"#include <unistd.h>#include <iostream>#include <boost/bind.hpp>using namespace std;void ThreadFunc(){    cout << "ThreadFunc..." << endl;}void ThreadFunc2(int count){    while( count_-- )    {        cout << "This is a test" << endl;        sleep(1);    }}class Foo{public:    Foo(int count) : count_(count){    }    void MemerFunc()    {        while( count_-- )        {            cout << "This is a test" << endl;            sleep(1);        }    }private:    int count_;};int main(void){    //Thread *t = new Thread(ThreadFunc);          //Thread *t = new Thread(boost::bind(ThreadFunc2,4));        Foo foo(3);    Thread *t = new Thread(boost::bind(&Foo::MemerFunc,&foo));    t->setAutoDelete(true);    t->start();    t->join();    //do other work....}
View Code

在上面的例子中我们可以绑定不同的对象到Thread的构造函数中,这样就可以实现随着绑定的不同调用不同的函数。

上面就是线程用面向对象和基于对象的不同封装方式,如果你要问,它们孰优孰劣,请挪步这篇精彩的分析。

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 米饭煮糊了锅怎么办 减肥吃了猪肉脯怎么办 吃了硬米饭胃痛怎么办 宝宝吃了硬物怎么办 米饭卡在喉咙里了怎么办 喉咙里卡了米饭怎么办 孕妇吃了坏鹅蛋怎么办 1岁大宝宝长短腿怎么办 行测中的判断推理怎么办 塑料盖子玻璃罐头瓶子打不开怎么办 猪肉烫火锅吃怎么办料 自制腊肠放干了怎么办 孕妇吃了4块腊肉怎么办 衣服沾了火锅味怎么办 皮包上有火锅味怎么办 芝士年糕裂开了怎么办 制作牛肉酱咸了怎么办 腌牛肉太咸了怎么办 八宝粥的拉环断了怎么办 八宝粥易拉罐拉环断了怎么办 吃完辣的胃难受怎么办 天天呆在家很烦怎么办 吃多了荔枝上火怎么办 猛犸牙牌子裂了怎么办 玩游戏电脑卡了怎么办 电脑打开卡在选项界面怎么办? 红警突然卡死怎么办 柯基不吃狗粮怎么办 貔貅嘴巴磕破了怎么办 开光貔貅牙磕了怎么办 玉貔貅鼻子碎了怎么办 开光的貔貅摔坏了怎么办 貔貅摔坏了耳朵怎么办? 貔貅摔坏了一点点怎么办 天猫删评价扣4分怎么办 暴风影音下载电视剧下载不了怎么办 fm2017引援电脑买了怎么办 退休时医保不够二十年怎么办 和的面迟迟不发怎么办 做面条的面发了怎么办 发不起来的面团怎么办