前幾天在學(xué)Windows多線程程序設(shè)計(jì),發(fā)現(xiàn)Win32 API用起來(lái)確實(shí)不怎么方便,特別是對(duì)于C++程序員。于是實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的封裝,技術(shù)含量當(dāng)然不高,不過(guò)用起來(lái)還是比較方便的。如果你熟悉Java,你會(huì)發(fā)現(xiàn)這個(gè)實(shí)現(xiàn)有點(diǎn)像Java的Thread,在Java中有兩種方法可以創(chuàng)建一個(gè)Thread:
1.從Thread類(lèi)繼承并實(shí)現(xiàn)run方法:
1?class?MyThread?extends
?Thread?{
2?????public?void
?run()?{
3?
????????...
4?
????}?
5?
};
6?
7?//開(kāi)啟線程
8?MyThread?thread?=?new
?MyThread;
9?thread.start();
2.聲明一個(gè)類(lèi)實(shí)現(xiàn)Runnable接口并實(shí)現(xiàn)run方法:
1?class?MyRunnable?implements
?Runnable?{
2?????public?void
?run()?{
3?
????????...
4?
????}
5?
};
6?
7?//?開(kāi)啟線程?
8?MyThread?thread?=?new?MyThread(new
?MyRunnable);
9?thread.start();
具體實(shí)現(xiàn)
Java的實(shí)現(xiàn)方式還算優(yōu)雅,我們也可以在C++中模擬,由于篇幅所限,在這里我們只關(guān)注基本功能的實(shí)現(xiàn):
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*/
在上面的代碼中我們先定義一個(gè)Runnable類(lèi),并為Runnable類(lèi)添加純虛函數(shù)run,需要特別注意的是Runnable類(lèi)的虛析構(gòu)函數(shù),任何想要成為基類(lèi)的class都應(yīng)該聲明析構(gòu)函數(shù)為virtual。
Thread類(lèi)直接繼承自Runnable,CLASS_UNCOPYABLE(Thread) 這一行用宏聲明Thread類(lèi)不可拷貝,具體細(xì)節(jié)請(qǐng)看
考慮用Macro替換Uncopyable 。start成員函數(shù)和Java中的一樣,用來(lái)開(kāi)啟一個(gè)線程,join成員函數(shù)用來(lái)阻塞當(dāng)前線程直到開(kāi)啟的線程執(zhí)行完畢。threadProc作為靜態(tài)成員函數(shù)用來(lái)傳遞給_beginthreadex,至于為什么用_beginthreadex代替CreateThread請(qǐng)問(wèn)Google。初步的實(shí)現(xiàn)都比較簡(jiǎn)單,直接貼上代碼:
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?}
下面是測(cè)試代碼:
test.cpp?1?#include?"thread.h"
?2?#include?<iostream>
?3?
?4?using?namespace?std;
?5?
?6?//第一種方法,從Thread類(lèi)繼承
?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?//第二種方法,“實(shí)現(xiàn)”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?}
可能的運(yùn)行結(jié)果:
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庫(kù),你會(huì)知道boost庫(kù)的Thread構(gòu)造函數(shù)可以接受普通函數(shù)和函數(shù)對(duì)象作為參數(shù),如果你覺(jué)得從Thread類(lèi)繼承或者實(shí)現(xiàn)Runnable接口還不夠簡(jiǎn)潔,下一篇會(huì)有一個(gè)比較好的改進(jìn)。