linux C++ 面向對象線程類封裝

1.封裝遇到的問題

pthread線程封裝爲抽象類,這樣用戶在使用線程時,只需要繼承一下這個抽象類,並實現相應的接口就可以了。這樣做的好處是用戶可以將注意力集中在線程所要執行的邏輯上,而不需要關注創建線程、銷燬線程等細節問題上。

我們抽象類的名稱爲Thread,其中有一個成員函數run,該函數爲的聲明形式爲:

void run() = 0;

即將該成員函數聲明爲純虛函數,用戶繼承此類必須要實現此成員函數。Thread中還有另外一個成員函數start,該函數的聲明形式爲:

void start();

用戶在子類中調用start方法,將啓動線程,並在線程中執行run函數。

最常想到的方法就是在start方法中使用pthread_create創建一個線程,並調用run函數。如下面這樣的實現:

  1. void start()   
  2. {   
  3.     int status;  
  4.    
  5.     status = pthread_create(_pThread,NULL,Thread::run,NULL);   
  6.     if(status != 0)   
  7.         err_abort(“creating thread failure”,status);   
  8.    
  9.  }   


這樣編譯肯定是不能通過的,這是因爲pthread_create要求的線程例程的接口形式爲:

void *(*thread_routin)(void *args);

而上面代碼中提供的線程例程的接口形式爲:

void Thread::run()

顯然不符合要求的接口。

爲了能夠在start中調用run函數,我們不得不採用一種迂迴的方式。下面提供兩種方法:一種是使用靜態成員函數,另外一種是使用友元函數。

       靜態成員函數的作用域是全局的,而不僅僅侷限於某個函數中。靜態成員函數的實現方法和C語言中的普通函數類似,因此靜態函數沒有this指針,靜態函數只能操作靜態成員變量。之所以將靜態函數封裝到類中,在很大程度上也只是爲了滿足面向對象的特性之一-----封裝性。

2.使用靜態函數

       需要特別注意的是mian函數中使用pthread_create的執行例程爲MyThread類中的線程代理函數thread_proxy_func,在此函數中在調用run函數,這樣就順利的迂迴到了run函數。基於這種方法,我們可以用靜態函數來封裝一個簡單的抽象類,以下爲封裝的代碼,由三個文件構成:Thread.h(類的聲明文件),Thread.cpp(類的實現文件),main.cpp(測試文件):

  1. #ifndef THREAD_H  
  2. #define THREAD_H  
  3. #include <iostream>  
  4. #include <pthread.h>  
  5.   
  6. using namespace std;  
  7.   
  8. class Thread  
  9. {  
  10. private:  
  11.     //當前線程的線程ID  
  12.     pthread_t tid;  
  13.     //線程的狀態  
  14.     int threadStatus;  
  15.     //獲取執行方法的指針  
  16.     static void * thread_proxy_func(void * args);  
  17.     //內部執行方法  
  18.     void* run1();  
  19. public:  
  20.     //線程的狀態-新建  
  21.     static const int THREAD_STATUS_NEW = 0;  
  22.     //線程的狀態-正在運行  
  23.     static const int THREAD_STATUS_RUNNING = 1;  
  24.     //線程的狀態-運行結束  
  25.     static const int THREAD_STATUS_EXIT = -1;  
  26.     //構造函數  
  27.     Thread();  
  28.     //線程的運行實體  
  29.     virtual void run()=0;  
  30.     //開始執行線程  
  31.     bool start();  
  32.     //獲取線程ID  
  33.     pthread_t getThreadID();  
  34.     //獲取線程狀態  
  35.     int getState();  
  36.     //等待線程直至退出  
  37.     void join();  
  38.     //等待線程退出或者超時  
  39.     void join(unsigned long millisTime);  
  40. };  
  41.   
  42. class MultiThread : public Thread  
  43. {  
  44. public:  
  45.     void run()  
  46.     {  
  47.         int number = 0;  
  48.         for (int i = 0; i < 10; i++)  
  49.         {  
  50.             cout << "Current number is " << number++;  
  51.             cout << " PID is " << getpid() << " TID is " << getThreadID() << endl;  
  52.             sleep(1);  
  53.         }  
  54.     }  
  55. };  
  56.   
  57. #endif  
Thread.cpp

  1. #include "thread.h"  
  2.   
  3.   
  4. void* Thread::run1()  
  5. {  
  6.     threadStatus = THREAD_STATUS_RUNNING;  
  7.     tid = pthread_self();  
  8.     run();  
  9.     threadStatus = THREAD_STATUS_EXIT;  
  10.     tid = 0;  
  11.     pthread_exit(NULL);  
  12. }  
  13.   
  14. Thread::Thread()  
  15. {  
  16.     tid = 0;  
  17.     threadStatus = THREAD_STATUS_NEW;  
  18. }  
  19.   
  20. bool Thread::start()  
  21. {  
  22.         int iRet = 0;  
  23.     pthread_create(&tid, NULL, thread_proxy_func, this) == 0;  
  24. }  
  25.   
  26. pthread_t Thread::getThreadID()  
  27. {  
  28.     return tid;  
  29. }  
  30.   
  31. int Thread::getState()  
  32. {  
  33.     return threadStatus;  
  34. }  
  35.   
  36. void Thread::join()  
  37. {  
  38.     if (tid > 0)  
  39.     {  
  40.         pthread_join(tid, NULL);  
  41.     }  
  42. }  
  43. void * Thread::thread_proxy_func(void * args)  
  44. {  
  45.         Thread * pThread = static_cast<Thread *>(args);   
  46.    
  47.         pThread->run();   
  48.           
  49.         return NULL;   
  50. }  
  51.   
  52. void Thread::join(unsigned long millisTime)  
  53. {  
  54.     if (tid == 0)  
  55.     {  
  56.         return;  
  57.     }  
  58.     if (millisTime == 0)  
  59.     {  
  60.         join();  
  61.     }else  
  62.     {  
  63.         unsigned long k = 0;  
  64.         while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)  
  65.         {  
  66.             usleep(100);  
  67.             k++;  
  68.         }  
  69.     }  
  70. }  
main.cpp

  1. #include <iostream>  
  2. #include <pthread.h>  
  3. #include "thread.h"  
  4.   
  5. using namespace std;  
  6.   
  7. int main(int argv,char *argc)  
  8. {  
  9.     MultiThread tt;  
  10.     tt.start();  
  11.     tt.join();  
  12.     return 0;  
  13. }  

3.使用友元函數

       友元函數的作用和靜態函數相同,都起到一個代理的作用。需要將對象的指針作爲參數傳遞給這個友元函數,然後在友元函數中調用run函數。代碼如下,

由三個文件構成:Thread.h(類的聲明文件),Thread.cpp(類的實現文件),main.cpp(測試文件):

Thread.h

  1. #ifndef THREAD_H  
  2. #define THREAD_H  
  3. #include <iostream>  
  4. #include <pthread.h>  
  5.   
  6. using namespace std;  
  7.   
  8. class Thread  
  9. {  
  10. private:  
  11.     //當前線程的線程ID  
  12.     pthread_t tid;  
  13.     //線程的狀態  
  14.     int threadStatus;  
  15.     //獲取執行方法的指針  
  16.     //static void * thread_proxy_func(void * args);  
  17.     friend void * thread_proxy_func(void * args);  
  18.     //內部執行方法  
  19.     void* run1();  
  20. public:  
  21.     //線程的狀態-新建  
  22.     static const int THREAD_STATUS_NEW = 0;  
  23.     //線程的狀態-正在運行  
  24.     static const int THREAD_STATUS_RUNNING = 1;  
  25.     //線程的狀態-運行結束  
  26.     static const int THREAD_STATUS_EXIT = -1;  
  27.     //構造函數  
  28.     Thread();  
  29.     //線程的運行實體  
  30.     virtual void run()=0;  
  31.     //開始執行線程  
  32.     bool start();  
  33.     //獲取線程ID  
  34.     pthread_t getThreadID();  
  35.     //獲取線程狀態  
  36.     int getState();  
  37.     //等待線程直至退出  
  38.     void join();  
  39.     //等待線程退出或者超時  
  40.     void join(unsigned long millisTime);  
  41. };  
  42.   
  43. class MultiThread : public Thread  
  44. {  
  45. public:  
  46.     void run()  
  47.     {  
  48.         int number = 0;  
  49.         for (int i = 0; i < 10; i++)  
  50.         {  
  51.             cout << "Current number is " << number++;  
  52.             cout << " PID is " << getpid() << " TID is " << getThreadID() << endl;  
  53.             sleep(1);  
  54.         }  
  55.     }  
  56. };  
  57.   
  58. #endif  

Thread.cpp

  1. #include "thread.h"  
  2.   
  3.   
  4. void* Thread::run1()  
  5. {  
  6.     threadStatus = THREAD_STATUS_RUNNING;  
  7.     tid = pthread_self();  
  8.     run();  
  9.     threadStatus = THREAD_STATUS_EXIT;  
  10.     tid = 0;  
  11.     pthread_exit(NULL);  
  12. }  
  13.   
  14. Thread::Thread()  
  15. {  
  16.     tid = 0;  
  17.     threadStatus = THREAD_STATUS_NEW;  
  18. }  
  19.   
  20. bool Thread::start()  
  21. {  
  22.         int iRet = 0;  
  23.     pthread_create(&tid, NULL, thread_proxy_func, this) == 0;  
  24. }  
  25.   
  26. pthread_t Thread::getThreadID()  
  27. {  
  28.     return tid;  
  29. }  
  30.   
  31. int Thread::getState()  
  32. {  
  33.     return threadStatus;  
  34. }  
  35.   
  36. void Thread::join()  
  37. {  
  38.     if (tid > 0)  
  39.     {  
  40.         pthread_join(tid, NULL);  
  41.     }  
  42. }  
  43. void * thread_proxy_func(void * args)  
  44. {  
  45.         Thread * pThread = static_cast<Thread *>(args);   
  46.    
  47.         pThread->run();   
  48.           
  49.         return NULL;   
  50. }  
  51.   
  52. void Thread::join(unsigned long millisTime)  
  53. {  
  54.     if (tid == 0)  
  55.     {  
  56.         return;  
  57.     }  
  58.     if (millisTime == 0)  
  59.     {  
  60.         join();  
  61.     }else  
  62.     {  
  63.         unsigned long k = 0;  
  64.         while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)  
  65.         {  
  66.             usleep(100);  
  67.             k++;  
  68.         }  
  69.     }  
  70. }  

main.cpp

  1. #include <iostream>  
  2. #include "thread.h"  
  3.   
  4. using namespace std;  
  5.   
  6. int main(int argv,char *argc)  
  7. {  
  8.     MultiThread tt;  
  9.     tt.start();  
  10.     tt.join();  
  11.     return 0;  
  12. }  

運行結果



makefile參考

[plain] view plain copy
  1. ANAME=server  
  2. CC=g++  
  3. TMP_PROGS = main.cpp thread.cpp  
  4. PROGS = $(TMP_PROGS)  
  5. OBJS = $(PROGS:.cpp=.o)  
  6. INCDIR=./  
  7.   
  8. all: $(ANAME)  
  9.   
  10. $(ANAME): $(OBJS)  
  11.     @echo "--------------- .o to ELT "  
  12.     $(CC) -g $(TMP_PROGS) -o $@ -lpthread   
  13. .cpp.o:  
  14.     @echo "--------------- CPP to .o "  
  15.     $(CC) -g $(CFLAGS) -I$(INCDIR) -c  $< -o $@  -lpthread   
  16.   
  17. clean:  
  18.     $(RM) $(ANAME)  
  19.     $(RM) *.o  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章