对posix线程机制的c++封装实现

 一直感觉Java的framework是学习OO设计非常优秀的范例。在Java中有对Thread非常方便的封装,重用起来十分方便,于是自己也想用C++对posix的pthread接口做一个类似的封装。
 
    事情没有想象那么简单,主要的问题出现在C和C++之间函数指针的转换上:
 
    来看下面一个类的定义:
 
typedef void*(*pFunc)(void*);
class Thread
{
    public:
    static void* run(void*)
    {
        cout<<"fn"<<endl;
    }
    void* runMember(void*)
    {
        cout<<"fn"<<endl;
    }
    virtual void* runVirtual(void*)
    {
        cout<<"fn"<<endl;   
    }
};
void pthread_create(pFunc){...}
 
    这里class Thread中有三个函数,一个static的,一个member,一个虚函数。请问,三个函数中哪一个可以作为参数传给pthead_create(pFunc)?
 
    C++语法定义不能强制类型转换的语法,一般都是编译器无法实现的语法。这里static void* run(void*)可以强制转换为C指针,而后两者不行。
 
    原因是对于runMember成员函数,编译器在编译时会将函数的第一个参数默认的分配给this指针。故C++与C函数指针实际上类型不匹配,编译器当然也无法把第一个this指针给你去了,否则函数里如果要调成员就更麻烦了。
    而对于runVirtual(void*),一来有同样的函数参数不匹配问题,二来对于含有virtual function的class,C++编译器会自动在类的内存空间内生成虚函数表,同时cpp编译器采取的标识虚函数的方式是为每一个虚函数保存一个id,调用虚函数通过虚函数表base+id的方式得到真实函数入口。故这里的runVirtual根据不同的编译实现,或许是虚函数表base值,或许是虚函数id。
    所以对于一个Thread类,可以这样实现:
(
   参考jdk的设计,thread可以通过两种方式创建,一是传函数指针(runnable接口)的方式直接创建THread对象,二是通过继承并扩展thread中run接口的方式创建thread。
)
//省略了错误处理的code
 
typedef void*(*PTHREADFUNC)(void*)
 
class Thread
{
public:
   Thread(PTHREADFUNC pTFunc):m_tid(0)
   {
       m_pthis = NULL;
       pthead_create(&m_tid,NULL,pTFunc,NULL);
       pthread_detach(m_tid);
   }
   Thread():m_tid(0)
   {
       m_pthis = this;
       pthead_create(&m_tid,NULL,&Thread::ThreadRun,NULL);
       pthread_detach(m_tid);
   }
    static void* ThreadRun(void*)
   {
       if(NULL != m_pthis)
       {
           m_pthis->run();
       }
   }
   virtual void run()=0;
private:
   staitc Thread *m_pthis;
   pthread_t m_tid;
};
 Thread * Thread::m_pthis = NULL;
 
 
这里通过一个adapter function : ThreadRun ,充当了C与C+代码中的Adapter。
用户类只需要扩展Thread类实现run()这个virtual方法,并创建类的实例就能实际线程。
 
当然上面这个Thread类还有很多问题:如1.不是线程安全的。因为用了一个static变量m_pthis保存this指针,所以需要使用者在创建自定义对象的前后在应用层中加锁保护。
2.并没有实现Java中那样的Runnable接口:像Java中那样通过对象基类(Interface)的方式传递回调函数是一种非常优雅的方法。要实现Runnable接口,可以在Runnable类中做和上面Thread类似的方法,用adapter function实现C对Cpp虚函数的调用。

再贴一个加锁版本的部分代码:

typedef void*(*pTFUNC)(void*);

class Thread
{
 public:
  Thread();
  Thread(pTFUNC runnable);
  virtual void run();
  static void* runGlobal(void*);
  static int detach(pthread_t tid);
  static int join(pthread_t tid,void **status);
  static void sleep(unsigned long);
  static void nsleep(unsigned long,unsigned long);
  static pthread_t self_id();
  pthread_t getThreadID();
  int getErrorCode();
 protected:
  void start();
  pTFUNC m_pRunnable;
  pthread_t m_tid;
  bool m_avaliable;
  int m_errorcode;
  static Thread* m_pthis;
  static pthread_mutex_t m_mutex;
 
};

Thread* Thread::m_pthis=NULL;
pthread_mutex_t Thread::m_mutex=PTHREAD_MUTEX_INITIALIZER;
Thread::Thread()
{
  m_pRunnable = NULL;
  m_tid = 0;
  m_avaliable = false;
  m_errorcode=0;
  pthread_mutex_lock(&m_mutex);
  m_pthis = this;
  start();
}

Thread::Thread(pTFUNC pRunnable)
{
  m_pRunnable = pRunnable;
  m_tid=0;
  m_avaliable = false;
  m_errorcode=0;
  m_pthis = this;
  start();
}

void Thread::run()
{
  return;
}

void* Thread::runGlobal(void *args)
{
  Thread *pLocal = m_pthis;
  pthread_mutex_unlock(&m_mutex);
  if(NULL != pLocal )
  {   
    pLocal->run();
  }
  return (void*)0;
}
void Thread::start()
{
  if( NULL!=m_pRunnable )
  {
    m_errorcode = pthread_create(&m_tid,NULL,m_pRunnable,NULL);
  }
  else
  {
    m_errorcode = pthread_create(&m_tid,NULL,(&Thread::runGlobal),NULL);
  }
  if(0==m_errorcode)
  {
    detach(m_tid);
    m_avaliable = true;
  }
  #ifdef _DEBUG
  printf("tid:%u,errorcode:%u,selfid:%u/n",m_tid,m_errorcode,pthread_self());
  #endif
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值