前几天在学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接口还不够简洁,下一篇会有一个比较好的改进。