如何完整的实现线程类

1.一般方法

    一般情况下,使用线程,是用pthread_create函数创建一个线程,创建的过程中采用传递函数指针的方式来实现主体的业务逻辑。比如

/*thread.c*/ 
#include <stdio.h> 
#include <pthread.h> 
 
/*线程一*/ 
void thread_1(void) 

    int i=0; 
    for(i=0;i<=6;i++) 
    { 
        printf("This is a pthread_1.\n"); 
        if(i==2) 
            pthread_exit(0); 
        sleep(1); 
    } 

 
/*线程二*/ 
void thread_2(void) 

    int i; 
    for(i=0;i<3;i++) 
        printf("This is a pthread_2.\n"); 
    pthread_exit(0); 

 
int main(void) 

    pthread_t id_1,id_2; 
    int i,ret; 
/*创建线程一*/ 
    ret=pthread_create(&id_1,NULL,(void  *) thread_1,NULL); 
    if(ret!=0) 
    { 
        printf("Create pthread error!\n"); 
    return -1; 
    } 
/*创建线程二*/ 
     ret=pthread_create(&id_2,NULL,(void  *) thread_2,NULL); 
    if(ret!=0) 
    { 
        printf("Create pthread error!\n"); 
    return -1; 
    } 
/*等待线程结束*/ 
    pthread_join(id_1,NULL); 
    pthread_join(id_2,NULL); 
    return 0; 

 在这以上这段代码中,首先实现了业务函数treahd_1等函数,再采用pthread_create函数创建线程,把函数指针传入,以便线程创建后调用函数。那么,在业务函数执行后,我们怎么判断线程有没有执行完呢(因为有时候,我们需要等待线程执行完后才能执行下一步的逻辑),通过函数ptread_join来判断。这几个函数的具体用法,可以百度。我们这里只讨论流程。

 

2.面向过程的方法

在上面的过程中,我们说道了普通的方法,如果采用面向对象的方法,该如何实现呢,有些人就说了,不就是进行封装嘛。。。不要忘记了。。。当你一旦调用pthread_create函数,就会立即调用你的业务函数pthread_1函数,封装的时候,如何先不执行业务函数呢?

 

第一步 完成一个纯虚函数,有什么用呢,让后面的线程类继承:

class IRunnable {
public:
    /**
     * 析构函数
     */
    virtual ~IRunnable() {}
   
    /**
     * 线程运行逻辑
     */
    virtual void run() = 0;
};

 

第二步,声明线程类

void* esRunThread(void* target) {
    try {
        reinterpret_cast<es::IRunnable*>(target)->run();
    } catch (es::SQLException& sqlEx) {
        cerr << "Uncaught exception in Thread::run(), " << sqlEx.what() << ", "
             << sqlEx.getSQLString() << endl;
    } catch (es::Exception& ex) {
        cerr << "Uncaught exception in Thread::run(), " << ex.what() << endl;
    } catch (...) {
        cerr << "Uncaught exception in Thread::run()" << endl;
    }
    return 0;
}

上面的代码,是把target进行类型转换为IRunnable,然后调用其run函数。

class Thread : public IRunnable{
public:

    typedef pthread_t ThreadId;

    Thread();

    Thread(IRunnable* target);

    virtual ~Thread();


    ThreadId getId() const;

 
    void start();

    void join();

    /**
     * 分离线程, 不允许等待已经join或detach过的线程
     */
    void detach();

    /**
     * 休眠线程
     * @param millis 休眠毫秒数
     */
    static void sleep(int millis);

    /**
     * 暂停当前线程让其它线程先运行
     */
    static void yield();


    static ThreadId getCurrentThreadId();

  
    virtual void run();

private:
    IRunnable*  _target;
    ThreadId    _id;
#endif
};

大家保持一点耐心,这里主要的函数是2个,一个 start,一个run。那么,看看这2个函数的实现

 

void Thread::start() {

    pthread_attr_t attr;
    int rc = pthread_attr_init(&attr);
    if (rc) {
        throw ThreadException(rc);
    }

    IRunnable* target = (_target ? _target : this);
    rc = pthread_create(&_id, &attr, ::esRunThread, target);
    if (rc) {
        throw ThreadException(errno);
    }
}

 

void Thread::run() {}

 

看到这里,大家看明白了吗?

这个Thread类,我们并不能直接拿来使用,为什么?因为他的run函数为空的,需要自己定义一个类,比如myThread来继承Thread,从而实现run函数。实现后,myThread.start()来启动该类。为什么start就能启动该类呢?

 

因为在start的过程中,创建了线程,参数当中传递的函数指针是esRunThread,函数的参数是target,而target实际上是用户自定实现的一个接口类(用来实现业务),如果没有实现该类,那么就默认为this(this实际就是用户自定义实现的线程类)。esRunThread函数把target强转后调用了run函数(用户实现的run函数),那么整个线程类的实现过程就完成了。

 

问大家一个小问题,如何保证让thread 不能被赋值拷贝?也就是防止pthread1=ptread2  ??

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值