从Win32 API封装Thread类[2]

转载 2007年10月15日 23:26:00

从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  蚂蚁终结者  

Win32 API 封装类总结

以下是一些封装的Win32 API类;备用; 重温WIN32 API ------ 最简单的Windows窗口封装类 http://blog.csdn.net/smstong/arti...
  • bcbobo21cn
  • bcbobo21cn
  • 2016年08月16日 10:56
  • 3522

重温WIN32 API ------ 最简单的Windows窗口封装类

如果你也厌倦了复杂的MFC,这里提供了一个非常简单的把C++类、对象与窗口类、对象联系起来的方式。...
  • smstong
  • smstong
  • 2015年01月04日 17:14
  • 11374

Win32API、MFC、.NET多线程并行求矩阵乘法(星星笔记)

1.运用Win32API实现,程序如下:
  • XX_123_1_RJ
  • XX_123_1_RJ
  • 2014年10月02日 21:20
  • 1658

Win32 API SDK 自绘窗口简单封装类

实现窗口简单的封装,新手笔记,大牛请多多指教 LoWindow.h 代码 /** * \file LoWindow.h * 自绘窗口的实现类 */ #pragma once...
  • lo106258
  • lo106258
  • 2016年11月07日 02:08
  • 880

[Win32] API Hook(2)在64位系统上的实现

本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/d...
  • zuishikonghuan
  • zuishikonghuan
  • 2015年08月25日 17:19
  • 4369

[Win32] SCManager 服务控制管理器API(2)

在上一篇博文“[Win32] SCManager 服务控制管理器API(1)”中(地址:http://blog.csdn.net/zuishikonghuan/article/details/4780...
  • zuishikonghuan
  • zuishikonghuan
  • 2015年08月21日 10:43
  • 2676

TrayIcon之Win32API封装类(vc6)

  • 2007年12月04日 09:47
  • 17KB
  • 下载

Win32 Api获取模块相关信息封装类CFileVersion

  • 2011年04月03日 20:56
  • 2KB
  • 下载

跟我一起学Windows界面封装(一) 之 基础篇:Win32 API

一、 初篇 Win32应用程序可以分成两大类:控制台程序和Windows窗口界面程序。其中控制台程序的入口是main(或_tmain),而窗口界面程序的入口函数是WinMain(或_tWinMain...
  • cheneywong
  • cheneywong
  • 2013年04月25日 09:15
  • 1467

重温WIN32 API ------ 一个简单的UDP服务器类

最近一个项目需要使用简单的UDP进行通信,为方便调用,使用C++类封装了一个简单的UDP服务器类。1 基本思路网络通信程序设计中最难的部分就是IO的处理,不同操作系统平台提供不同的IO处理机制,Win...
  • smstong
  • smstong
  • 2014年12月22日 18:07
  • 3416
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:从Win32 API封装Thread类[2]
举报原因:
原因补充:

(最多只允许输入30个字)