前幾天在學Windows多線程程序設計,發現Win32 API用起來確實不怎么方便,特別是對于C++程序員。于是實現了一個簡單的封裝,技術含量當然不高,不過用起來還是比較方便的。如果你熟悉Java,你會發現這個實現有點像Java的Thread,在Java中有兩種方法可以創建一個Thread:
1.從Thread類繼承并實現run方法:
1?class?MyThread?extends
?Thread?{
2?????public?void
?run()?{
3?
????????...
4?
????}?
5?
};
6?
7?//開啟線程
8?MyThread?thread?=?new
?MyThread;
9?thread.start();
2.聲明一個類實現Runnable接口并實現run方法:
1?class?MyRunnable?implements
?Runnable?{
2?????public?void
?run()?{
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?????else
39?????????p->run();
40?????return?0;
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?????return?0;
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接口還不夠簡潔,下一篇會有一個比較好的改進。