从Win32 API封装Thread类[2]
在上一篇中介绍了创建Thread的两种方法:从Thread类继承或者实现Runnable接口。有时候这并不是特别方便,我们需要的是更灵活的方法,比如像boost库中的Thread一样可以用普通函数和函数对象( functor and function object)作为构造函数参数。如果你熟悉STL,你应该熟悉bind1st和bind2nd这两个函数配接器( function adapter),bind1st和bind2nd可以将一个二元函数( binary function)转换成一元函数( unary function)。为了使Thread类能够用普通函数和函数对象作为参数,我们需要一个bind将一元函数转换成无参函数:
bind.h
1
#ifndef BIND_H
2 #define BIND_H
3
4 template < class _Result >
5 struct trivial_function {
6 typedef _Result result_type;
7 };
8
9 template < class _Operation >
10 class binder : public trivial_function < typename _Operation::result_type > {
11 public :
12 binder( const _Operation & x, const typename _Operation::argument_type & y)
13 :op(x), value(y) {}
14 typename _Operation::result_type operator()() const {
15 return op(value);
16 }
17 protected :
18 _Operation op;
19 typename _Operation::argument_type value;
20 };
21
22 template < class _Operation, class _Tp >
23 inline binder < _Operation >
24 bind( const _Operation & __fn, const _Tp & __x)
25 {
26 typedef typename _Operation::argument_type _Arg_type;
27 return binder < _Operation > (__fn, _Arg_type(__x));
28 }
29
30 #endif /* BIND_H */
2 #define BIND_H
3
4 template < class _Result >
5 struct trivial_function {
6 typedef _Result result_type;
7 };
8
9 template < class _Operation >
10 class binder : public trivial_function < typename _Operation::result_type > {
11 public :
12 binder( const _Operation & x, const typename _Operation::argument_type & y)
13 :op(x), value(y) {}
14 typename _Operation::result_type operator()() const {
15 return op(value);
16 }
17 protected :
18 _Operation op;
19 typename _Operation::argument_type value;
20 };
21
22 template < class _Operation, class _Tp >
23 inline binder < _Operation >
24 bind( const _Operation & __fn, const _Tp & __x)
25 {
26 typedef typename _Operation::argument_type _Arg_type;
27 return binder < _Operation > (__fn, _Arg_type(__x));
28 }
29
30 #endif /* BIND_H */
有了bind我们还需要修改Thread类的构造函数,显然我们必须将构造函数声明为成员模板(还有一种方法也可以达到同样的目的,就是把Thread类声明为模板,但是这样的设计好像不太好),这样才能够让Thread类的构造函数可以接受各种类型的参数,修改后的构造函数应该能够使用如下三种类型的参数:
1.Runnable *
2.no argument function
3.no argument functor
下面是修改后的头文件:
runnable.h
1
#ifndef RUNNABLE_H
2 #define RUNNABLE_H
3
4 struct Runnable {
5 virtual void run() = 0 ;
6 virtual ~ Runnable() {}
7 };
8
9 template < class T >
10 class RunnableFunctor : public Runnable {
11 public :
12 RunnableFunctor( const T & f) :_func(f) {}
13 virtual void run() { _func(); }
14 private :
15 T _func;
16 };
17
18 // base template for no argument functor
19 template < class T >
20 struct FuncImpl {
21 static Runnable * transfer( const T & t) {
22 return new RunnableFunctor < T > (t);
23 }
24 };
25
26 // partial specialization for T*
27 template < class T >
28 struct FuncImpl < T *> {
29 static Runnable * transfer(T * t) {
30 return t;
31 }
32 };
33
34 // partial specialization for no argument function
35 template < class T >
36 struct FuncImpl < T ( * )() > {
37 static Runnable * transfer(T ( * t)()) {
38 return new RunnableFunctor < T ( * )() > (t);
39 }
40 };
41
42 template < class T >
43 inline Runnable * transfer( const T & t) {
44 return FuncImpl < T > ::transfer(t);
45 }
46
47 #endif /* RUNNABLE_H */
2 #define RUNNABLE_H
3
4 struct Runnable {
5 virtual void run() = 0 ;
6 virtual ~ Runnable() {}
7 };
8
9 template < class T >
10 class RunnableFunctor : public Runnable {
11 public :
12 RunnableFunctor( const T & f) :_func(f) {}
13 virtual void run() { _func(); }
14 private :
15 T _func;
16 };
17
18 // base template for no argument functor
19 template < class T >
20 struct FuncImpl {
21 static Runnable * transfer( const T & t) {
22 return new RunnableFunctor < T > (t);
23 }
24 };
25
26 // partial specialization for T*
27 template < class T >
28 struct FuncImpl < T *> {
29 static Runnable * transfer(T * t) {
30 return t;
31 }
32 };
33
34 // partial specialization for no argument function
35 template < class T >
36 struct FuncImpl < T ( * )() > {
37 static Runnable * transfer(T ( * t)()) {
38 return new RunnableFunctor < T ( * )() > (t);
39 }
40 };
41
42 template < class T >
43 inline Runnable * transfer( const T & t) {
44 return FuncImpl < T > ::transfer(t);
45 }
46
47 #endif /* RUNNABLE_H */
thread.h
1
#ifndef THREAD_H
2 #define THREAD_H
3
4 #include < windows.h >
5 #include " bind.h "
6 #include " runnable.h "
7
8 #define CLASS_UNCOPYABLE(classname) \
9 private : \
10 classname( const classname & ); \
11 classname & operator = ( const classname & );
12
13 class Thread : public Runnable {
14 CLASS_UNCOPYABLE(Thread)
15 public :
16 Thread()
17 :_target( 0 )
18 ,_handle( 0 ) {
19
20 }
21 template < class T >
22 explicit Thread( const T & op)
23 :_target(transfer(op))
24 ,_handle( 0 ) {
25
26 }
27 virtual ~ Thread();
28 virtual void run() {}
29 void start();
30 void join();
31 private :
32 static unsigned __stdcall threadProc( void * param);
33 private :
34 Runnable * _target;
35 HANDLE _handle;
36 };
37
38 #endif /* THREAD_H */
2 #define THREAD_H
3
4 #include < windows.h >
5 #include " bind.h "
6 #include " runnable.h "
7
8 #define CLASS_UNCOPYABLE(classname) \
9 private : \
10 classname( const classname & ); \
11 classname & operator = ( const classname & );
12
13 class Thread : public Runnable {
14 CLASS_UNCOPYABLE(Thread)
15 public :
16 Thread()
17 :_target( 0 )
18 ,_handle( 0 ) {
19
20 }
21 template < class T >
22 explicit Thread( const T & op)
23 :_target(transfer(op))
24 ,_handle( 0 ) {
25
26 }
27 virtual ~ Thread();
28 virtual void run() {}
29 void start();
30 void join();
31 private :
32 static unsigned __stdcall threadProc( void * param);
33 private :
34 Runnable * _target;
35 HANDLE _handle;
36 };
37
38 #endif /* THREAD_H */
thread.cpp和前一篇的几乎一样,唯一的不同是去掉了构造函数Thread(Runnable *),因为现在的构造函数改成了成员模板,实现也放在thread.h中了。现在的构造函数能够接受各种类型的参数,主要归功于模板函数transfer,实现代码在runnable.h中,主要技巧是用类的偏特化模拟函数模板的偏特化,不明白的请看 为什么不要特化函数模版。
下面是测试代码:
test.cpp
1
#include
"
thread.h
"
2 #include < iostream >
3 #include < functional >
4
5 using namespace std;
6
7 // no argument function
8 void print() {
9 cout << " print " << endl;
10 }
11
12 // unary function
13 void print1( int n) {
14 cout << " print1 " << endl;
15 }
16
17 // binary function
18 void print2( int m, int n) {
19 cout << " print2 " << endl;
20 }
21
22
23 // no argument functor
24 struct PrintFunctor {
25 void operator()() const {
26 cout << " PrintFunctor " << endl;
27 }
28 };
29
30 // unary functor
31 struct PrintFunctor1 : public unary_function < int , void > {
32 void operator()( int n) const {
33 cout << " PrintFunctor1 " << endl;
34 }
35 };
36
37 // binary functor
38 struct PrintFunctor2 : public binary_function < int , int , void > {
39 void operator()( int m, int n) const {
40 cout << " PrintFunctor2 " << endl;
41 }
42 };
43
44 int main() {
45
46 // construct Thread with no argument function
47 Thread thread1( & print);
48 thread1.start();
49
50 // construct Thread with unary function
51 Thread thread2(bind(ptr_fun(print1), 5 ));
52 thread2.start();
53
54 // construct Thread with binary function
55 Thread thread3(bind(bind1st(ptr_fun(print2), 1 ), 2 ));
56 thread3.start();
57
58
59 // construct Thread with no argument functor
60 Thread thread4((PrintFunctor()));
61 thread4.start();
62
63 // construct Thread with unary functor
64 Thread thread5(bind(PrintFunctor1(), 5 ));
65 thread5.start();
66
67 // construct Thread with binary functor
68 Thread thread6(bind(bind1st(PrintFunctor2(), 1 ), 2 ));
69 thread6.start();
70
71 thread1.join();
72 thread2.join();
73 thread3.join();
74 thread4.join();
75 thread5.join();
76 thread6.join();
77
78 return 0 ;
79 }
2 #include < iostream >
3 #include < functional >
4
5 using namespace std;
6
7 // no argument function
8 void print() {
9 cout << " print " << endl;
10 }
11
12 // unary function
13 void print1( int n) {
14 cout << " print1 " << endl;
15 }
16
17 // binary function
18 void print2( int m, int n) {
19 cout << " print2 " << endl;
20 }
21
22
23 // no argument functor
24 struct PrintFunctor {
25 void operator()() const {
26 cout << " PrintFunctor " << endl;
27 }
28 };
29
30 // unary functor
31 struct PrintFunctor1 : public unary_function < int , void > {
32 void operator()( int n) const {
33 cout << " PrintFunctor1 " << endl;
34 }
35 };
36
37 // binary functor
38 struct PrintFunctor2 : public binary_function < int , int , void > {
39 void operator()( int m, int n) const {
40 cout << " PrintFunctor2 " << endl;
41 }
42 };
43
44 int main() {
45
46 // construct Thread with no argument function
47 Thread thread1( & print);
48 thread1.start();
49
50 // construct Thread with unary function
51 Thread thread2(bind(ptr_fun(print1), 5 ));
52 thread2.start();
53
54 // construct Thread with binary function
55 Thread thread3(bind(bind1st(ptr_fun(print2), 1 ), 2 ));
56 thread3.start();
57
58
59 // construct Thread with no argument functor
60 Thread thread4((PrintFunctor()));
61 thread4.start();
62
63 // construct Thread with unary functor
64 Thread thread5(bind(PrintFunctor1(), 5 ));
65 thread5.start();
66
67 // construct Thread with binary functor
68 Thread thread6(bind(bind1st(PrintFunctor2(), 1 ), 2 ));
69 thread6.start();
70
71 thread1.join();
72 thread2.join();
73 thread3.join();
74 thread4.join();
75 thread5.join();
76 thread6.join();
77
78 return 0 ;
79 }
当然了,上面的并不是全部,修改后的Thread类不仅能够使用原先的从Thread类继承或者实现Runnable接口的方法,还可以使用任何无参函数或无参函数对象。除了test.cpp里示范的,你甚至可以用bind,bind1st,bind2st,mem_fun,mem_fun_ref的组合来用某个类的成员函数作为参数,具有超强的灵活性。
目前实现的这些都是Thread类最基本的功能,其他功能如设置线程优先级,挂起或恢复线程,异常处理等具体实现都比较简单,这这里就不一一实现了。
源代码下载: 点击下载