从Win32 API封装Thread类[2]

从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 */

有了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 */

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 */

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  }

当然了,上面的并不是全部,修改后的Thread类不仅能够使用原先的从Thread类继承或者实现Runnable接口的方法,还可以使用任何无参函数或无参函数对象。除了test.cpp里示范的,你甚至可以用bind,bind1st,bind2st,mem_fun,mem_fun_ref的组合来用某个类的成员函数作为参数,具有超强的灵活性。

目前实现的这些都是Thread类最基本的功能,其他功能如设置线程优先级,挂起或恢复线程,异常处理等具体实现都比较简单,这这里就不一一实现了。
源代码下载: 点击下载

你可能感兴趣的:(从Win32 API封装Thread类[2])