1.封裝遇到的問題
將pthread線程封裝爲抽象類,這樣用戶在使用線程時,只需要繼承一下這個抽象類,並實現相應的接口就可以了。這樣做的好處是用戶可以將注意力集中在線程所要執行的邏輯上,而不需要關注創建線程、銷燬線程等細節問題上。
我們抽象類的名稱爲Thread,其中有一個成員函數run,該函數爲的聲明形式爲:
void run() = 0;
即將該成員函數聲明爲純虛函數,用戶繼承此類必須要實現此成員函數。Thread中還有另外一個成員函數start,該函數的聲明形式爲:
void start();
用戶在子類中調用start方法,將啓動線程,並在線程中執行run函數。
最常想到的方法就是在start方法中使用pthread_create創建一個線程,並調用run函數。如下面這樣的實現:
- void start()
- {
- int status;
- status = pthread_create(_pThread,NULL,Thread::run,NULL);
- if(status != 0)
- err_abort(“creating thread failure”,status);
- }
這樣編譯肯定是不能通過的,這是因爲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(測試文件):
- #ifndef THREAD_H
- #define THREAD_H
- #include <iostream>
- #include <pthread.h>
- using namespace std;
- class Thread
- {
- private:
- //當前線程的線程ID
- pthread_t tid;
- //線程的狀態
- int threadStatus;
- //獲取執行方法的指針
- static void * thread_proxy_func(void * args);
- //內部執行方法
- void* run1();
- public:
- //線程的狀態-新建
- static const int THREAD_STATUS_NEW = 0;
- //線程的狀態-正在運行
- static const int THREAD_STATUS_RUNNING = 1;
- //線程的狀態-運行結束
- static const int THREAD_STATUS_EXIT = -1;
- //構造函數
- Thread();
- //線程的運行實體
- virtual void run()=0;
- //開始執行線程
- bool start();
- //獲取線程ID
- pthread_t getThreadID();
- //獲取線程狀態
- int getState();
- //等待線程直至退出
- void join();
- //等待線程退出或者超時
- void join(unsigned long millisTime);
- };
- class MultiThread : public Thread
- {
- public:
- void run()
- {
- int number = 0;
- for (int i = 0; i < 10; i++)
- {
- cout << "Current number is " << number++;
- cout << " PID is " << getpid() << " TID is " << getThreadID() << endl;
- sleep(1);
- }
- }
- };
- #endif
- #include "thread.h"
- void* Thread::run1()
- {
- threadStatus = THREAD_STATUS_RUNNING;
- tid = pthread_self();
- run();
- threadStatus = THREAD_STATUS_EXIT;
- tid = 0;
- pthread_exit(NULL);
- }
- Thread::Thread()
- {
- tid = 0;
- threadStatus = THREAD_STATUS_NEW;
- }
- bool Thread::start()
- {
- int iRet = 0;
- pthread_create(&tid, NULL, thread_proxy_func, this) == 0;
- }
- pthread_t Thread::getThreadID()
- {
- return tid;
- }
- int Thread::getState()
- {
- return threadStatus;
- }
- void Thread::join()
- {
- if (tid > 0)
- {
- pthread_join(tid, NULL);
- }
- }
- void * Thread::thread_proxy_func(void * args)
- {
- Thread * pThread = static_cast<Thread *>(args);
- pThread->run();
- return NULL;
- }
- void Thread::join(unsigned long millisTime)
- {
- if (tid == 0)
- {
- return;
- }
- if (millisTime == 0)
- {
- join();
- }else
- {
- unsigned long k = 0;
- while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
- {
- usleep(100);
- k++;
- }
- }
- }
- #include <iostream>
- #include <pthread.h>
- #include "thread.h"
- using namespace std;
- int main(int argv,char *argc)
- {
- MultiThread tt;
- tt.start();
- tt.join();
- return 0;
- }
3.使用友元函數
友元函數的作用和靜態函數相同,都起到一個代理的作用。需要將對象的指針作爲參數傳遞給這個友元函數,然後在友元函數中調用run函數。代碼如下,
由三個文件構成:Thread.h(類的聲明文件),Thread.cpp(類的實現文件),main.cpp(測試文件):
Thread.h- #ifndef THREAD_H
- #define THREAD_H
- #include <iostream>
- #include <pthread.h>
- using namespace std;
- class Thread
- {
- private:
- //當前線程的線程ID
- pthread_t tid;
- //線程的狀態
- int threadStatus;
- //獲取執行方法的指針
- //static void * thread_proxy_func(void * args);
- friend void * thread_proxy_func(void * args);
- //內部執行方法
- void* run1();
- public:
- //線程的狀態-新建
- static const int THREAD_STATUS_NEW = 0;
- //線程的狀態-正在運行
- static const int THREAD_STATUS_RUNNING = 1;
- //線程的狀態-運行結束
- static const int THREAD_STATUS_EXIT = -1;
- //構造函數
- Thread();
- //線程的運行實體
- virtual void run()=0;
- //開始執行線程
- bool start();
- //獲取線程ID
- pthread_t getThreadID();
- //獲取線程狀態
- int getState();
- //等待線程直至退出
- void join();
- //等待線程退出或者超時
- void join(unsigned long millisTime);
- };
- class MultiThread : public Thread
- {
- public:
- void run()
- {
- int number = 0;
- for (int i = 0; i < 10; i++)
- {
- cout << "Current number is " << number++;
- cout << " PID is " << getpid() << " TID is " << getThreadID() << endl;
- sleep(1);
- }
- }
- };
- #endif
Thread.cpp
- #include "thread.h"
- void* Thread::run1()
- {
- threadStatus = THREAD_STATUS_RUNNING;
- tid = pthread_self();
- run();
- threadStatus = THREAD_STATUS_EXIT;
- tid = 0;
- pthread_exit(NULL);
- }
- Thread::Thread()
- {
- tid = 0;
- threadStatus = THREAD_STATUS_NEW;
- }
- bool Thread::start()
- {
- int iRet = 0;
- pthread_create(&tid, NULL, thread_proxy_func, this) == 0;
- }
- pthread_t Thread::getThreadID()
- {
- return tid;
- }
- int Thread::getState()
- {
- return threadStatus;
- }
- void Thread::join()
- {
- if (tid > 0)
- {
- pthread_join(tid, NULL);
- }
- }
- void * thread_proxy_func(void * args)
- {
- Thread * pThread = static_cast<Thread *>(args);
- pThread->run();
- return NULL;
- }
- void Thread::join(unsigned long millisTime)
- {
- if (tid == 0)
- {
- return;
- }
- if (millisTime == 0)
- {
- join();
- }else
- {
- unsigned long k = 0;
- while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
- {
- usleep(100);
- k++;
- }
- }
- }
main.cpp
- #include <iostream>
- #include "thread.h"
- using namespace std;
- int main(int argv,char *argc)
- {
- MultiThread tt;
- tt.start();
- tt.join();
- return 0;
- }
運行結果
makefile參考
- ANAME=server
- CC=g++
- TMP_PROGS = main.cpp thread.cpp
- PROGS = $(TMP_PROGS)
- OBJS = $(PROGS:.cpp=.o)
- INCDIR=./
- all: $(ANAME)
- $(ANAME): $(OBJS)
- @echo "--------------- .o to ELT "
- $(CC) -g $(TMP_PROGS) -o $@ -lpthread
- .cpp.o:
- @echo "--------------- CPP to .o "
- $(CC) -g $(CFLAGS) -I$(INCDIR) -c $< -o $@ -lpthread
- clean:
- $(RM) $(ANAME)
- $(RM) *.o