類成員函數作為pthread_create函數參數


http://blog.csdn.net/luo6620378xu/article/details/8521940

    近日需要將線程池封裝成C++類,類名為Threadpool。在類的成員函數exec_task中調用pthread_create去啟動線程執行例程thread_rounter。編譯之后報錯如下:

spfs_threadpool.cpp: In member function ‘int Threadpool::exec_task(task*)’:

spfs_threadpool.cpp:174: error: argument of type ‘void* (Threadpool::)(void*)’ does not match ‘void* (*)(void*)’

    出現類型不匹配的問題。因為pthread_create需要的參數類型為void* (*)(void*),而thread_rounter作為類的成員函數時其類型是void* (Threadpool::)(void*)的成員函數指針。我們知道類的成員函數在經過編譯器處理之后,會變成帶有this指針參數的全局函數,所以類型注定是不會匹配的。但是如果將thread_rounter聲明為static類型,那么編譯器會將static形式的函數,轉換成不帶this指針的全局函數,所以其類型可以與pthread_create需要的參數類型相匹配。但是類的靜態成員函數無法訪問類的非靜態成員,不過這可以通過傳遞this指針解決這個問題。

綜上,我的這個問題可以這個樣子解決。

出問題之前的代碼:

void *thread_rounter(void *)//線程執行函數

{

   //直接訪問類的成員

}

 

exec_task函數中調用:

pthread_create(&tid,NULL,thread_rounter,NULL);//啟動線程執行例程

 

修復這個問題的代碼:

static void *thread_rounter(void *tmp)/線程執行函數

{

  Threadpool *p=(Threadpool *)tmp;

    //通過p指針間接訪問類的非靜態成員

 

}

 

exec_task函數中調用:

pthread_create(&tid,NULL,thread_rounter,(void *)this);//啟動線程執行例程

----------------------------------------------------------------------------------------------------------------------

 

在網上搜索一下還有其他的解決方案,摘錄如下,為了以示尊重標明文章來源,感謝原文作者。

 

方案二:

將線程啟動函數聲明為模板函數。

摘錄自:http://hi.baidu.com/angelevil2006/item/e1806ec30574ff11515058d1

[cpp]  view plain  copy
 
  1. template <typename TYPE, void (TYPE::*_RunThread)() >  
  2. void* _thread_t(void* param)//線程啟動函數,聲明為模板函數  
  3. {     
  4.  TYPE* This = (TYPE*)param;     
  5.  This->_RunThread();     
  6.  return NULL;  
  7.  }  
  8.    
  9.  class MyClass  
  10.  {  
  11.  public:    
  12.  MyClass();   
  13.  void _RunThread();  
  14.    
  15.  private:    
  16.  pthread_t tid;    
  17.  };  
  18.    
  19.  void MyClass::_RunThread()  
  20.  {     
  21.  this->DoSomeThing();     
  22.  }  
  23.    
  24.  MyClass::MyClass()  
  25.  {     
  26.  pthread_create(&tid, NULL, _thread_t<MyClass, &MyClass::_RunThread>, this);  
  27.  }       
  28.    
  29.    
  30.  //函數模版不單可以替換類型本身,還能替換類型的成員函數。  
  31.  //注意:      1、名稱只能是_RunThread,不能在指定模版參數的時候修改;           
  32.  //  2、_RunThread只能是public的,除非把_thread_t定義到MyClass的內部。  
  33.    
  34.    
  35.    

 

采取這個方案放入我的項目中:

 

出問題之前的代碼:

void *thread_rounter(void *)//線程執行函數

{

   //直接訪問類的成員

}

 

exec_task函數中調用:

pthread_create(&tid,NULL,thread_rounter,NULL);//啟動線程執行例程

 

修復這個問題的代碼:

添加public成員函數:

 

void Run()

{

  //該函數替換上述thread_rounter的執行代碼

}

 

thread_rounter修改為全局模板函數:

 

template <typename TYPE, void (TYPE::*Run)() >

void * thread_rounter(void * param)

{

    TYPE *p=(TYPE*)param;

    p->Run();

    return NULL;

}

 

exec_task函數中調用:

pthread_create(&tid,NULL,thread_rounter<Threadpool,&Threadpool::Run>,(void *)this);

 

總結:

解決這個問題的關鍵在於想方設法使啟動函數指針滿足void*(*)(void *)類型。

 

將啟動函數改寫成static成員函數適用於可以修改類的源代碼的情況。

 

而將啟動函數寫成模板函數還可以適用於沒有類的源代碼的情況,自己寫一個類,公共繼承自原類,添加啟動函數為模板函數即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM