從Win32 API封裝Thread類[1]
阿新 • • 發佈:2018-12-27
前幾天在學Windows多執行緒程式設計,發現Win32 API用起來確實不怎麼方便,特別是對於C++程式設計師。於是實現了一個簡單的封裝,技術含量當然不高,不過用起來還是比較方便的。如果你熟悉Java,你會發現這個實現有點像Java的Thread,在Java中有兩種方法可以建立一個Thread:
1.從Thread類繼承並實現run方法:
2 publicvoid run() {
3 ...
5 };
6 7 //開啟執行緒 8 MyThread thread =new MyThread;
9 thread.start();
2.宣告一個類實現Runnable介面並實現run方法:
1 class MyRunnable implements Runnable {2
3 ...
4 }
5 };
6 7 // 開啟執行緒 8 MyThread thread =new MyThread(new MyRunnable);
9 thread.start();
具體實現
Java的實現方式還算優雅,我們也可以在C++中模擬,由於篇幅所限,在這裡我們只關注基本功能的實現:
thread.h
1 #ifndef THREAD_H
2 #define THREAD_H
3 4 #include <windows.h> 5 6 #define CLASS_UNCOPYABLE(classname) \
7 private: \
8 classname(const classname&); \
9 classname& operator=(const classname&);
10 11 struct Runnable {
12 virtual void run() =0;
13 virtual ~Runnable() {}
14 };
15 16 class Thread : public Runnable {
17 CLASS_UNCOPYABLE(Thread)
18 public:
19 explicit Thread(Runnable* target =0);
20 virtual ~Thread();
21 virtual void run() {}
22 void start();
23 void join();
24 private:
25 static unsigned __stdcall threadProc(void* param);
26 private:
27 Runnable* _target;
28 HANDLE _handle;
29 };
30 31 #endif/*THREAD_H*/
在上面的程式碼中我們先定義一個Runnable類,併為Runnable類新增純虛擬函式run,需要特別注意的是Runnable類的虛解構函式,任何想要成為基類的class都應該宣告解構函式為virtual。
Thread類直接繼承自Runnable,CLASS_UNCOPYABLE(Thread) 這一行用巨集宣告Thread類不可拷貝,具體細節請看 考慮用Macro替換Uncopyable 。start成員函式和Java中的一樣,用來開啟一個執行緒,join成員函式用來阻塞當前執行緒直到開啟的執行緒執行完畢。threadProc作為靜態成員函式用來傳遞給_beginthreadex,至於為什麼用_beginthreadex代替CreateThread請問Google。初步的實現都比較簡單,直接貼上程式碼:
thread.cpp
1 #include "thread.h" 2 #include <process.h>// for _beginthreadex 3 4 Thread::Thread(Runnable* target /*= 0*/)
5 :_target(target)
6 ,_handle(0) {
7 8 }
9 10 Thread::~Thread() {
11 if (_handle !=0)
12 CloseHandle(_handle);
13 if (_target !=0)
14 delete _target;
15 }
16 17 void Thread::start() {
18 if (_handle !=0)
19 return;
20 unsigned id;
21 _handle = reinterpret_cast<HANDLE>(
22 _beginthreadex(0, 0, threadProc, this, 0, &id)
23 );
24 }
25 26 void Thread::join() {
27 if(_handle !=0) {
28 WaitForSingleObject(_handle, INFINITE);
29 CloseHandle(_handle);
30 _handle =0;
31 }
32 }
33 34 unsigned __stdcall Thread::threadProc(void* param) {
35 Thread* p = static_cast<Thread*>(param);
36 if (p->_target !=0)
37 p->_target->run();
38 else39 p->run();
40 return0;
41 }
下面是測試程式碼:
test.cpp
1 #include "thread.h" 2 #include <iostream> 3 4 using namespace std;
5 6 //第一種方法,從Thread類繼承 7 struct MyThread : public Thread {
8 virtual void run() {
9 for (int i =0; i <5; ++i) {
10 cout <<"MyThread Running..."<< i << endl;
11 Sleep(100);
12 }
13 }
14 };
15 16 //第二種方法,“實現”Runnable介面17 struct MyRunnable : public Runnable {
18 virtual void run() {
19 for (int i =0; i <5; ++i) {
20 cout <<"MyRunnable Running..."<< i << endl;
21 Sleep(300);
22 }
23 }
24 };
25 26 int main() {
27 28 MyThread thread1;
29 Thread thread2(new MyRunnable());
30 thread1.start();
31 thread2.start();
32 thread1.join();
33 thread2.join();
34 35 return0;
36 }
可能的執行結果:
MyThread Running...0
MyRunnable Running...0
MyThread Running...1
MyThread Running...2
MyRunnable Running...1
MyThread Running...3
MyThread Running...4
MyRunnable Running...2
MyRunnable Running...3
MyRunnable Running...4
如果你熟悉boost庫,你會知道boost庫的Thread建構函式可以接受普通函式和函式物件作為引數,如果你覺得從Thread類繼承或者實現Runnable介面還不夠簡潔,下一篇會有一個比較好的改進。
posted on 2007-08-30 10:18 螞蟻終結者 閱讀(4219) 評論(8) 編輯 收藏 引用 所屬分類: C++