从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<*>  {
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<intvoid>  {
32     void operator()(int n) const
 {
33         cout << "PrintFunctor1" <<
 endl;
34 
    }
35 
};
36 

37 //binary functor
38 struct PrintFunctor2 : public binary_function<intintvoid>  {
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类最基本的功能,其他功能如设置线程优先级,挂起或恢复线程,异常处理等具体实现都比较简单,这这里就不一一实现了。
源代码下载: 点击下载

posted by  蚂蚁终结者  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值