寫完上一篇日志"靜態回調函數到成員函數的轉換", 問了一下石教主有什么看法, 結果不問不知道, 一問才發現自己徹底土了, 這個問題用boost::bind可以解決得這么好, 調用的函數參數個數都可以沒有限制... 唉, 以后還是要好好學習
ps. 不過不知道這個方法運行效率怎么樣, 還要繼續試驗
// 下面的內容于2007年5月4日改成最后用的版本了
實現的功能:
(1) 用于把非多線程的代碼改成多線程
(2) 普通Thread與Work Item for Thread Pool不相區別
(3) 所用的類成員函數參數個數不限(依bind參數限制來定,一般夠用了)
1
#pragma once
2
3
#include <vector>
4
#include <list>
5
#include <boost/any.hpp>
6
#include <boost/bind.hpp>
7
#include <map>
8
9
/**//************************************************************************/
10
/**//* Code Sample: */
11
/**//************************************************************************/
12
/**//*
13
14
#define _WIN32_WINNT 0x0500
15
#include <windows.h>
16
#include <iostream>
17
#include "ThreadHelper.h"
18
19
CRITICAL_SECTION cs;
20
21
struct A
22
{
23
int f1(int a, int b){
24
EnterCriticalSection(&cs);
25
std::cout<<a<<"+"<<b<<"="<<a+b<<"\n";
26
LeaveCriticalSection(&cs);
27
return a+b;
28
}
29
30
HANDLE ExecuteInThread(int i, int j){
31
return ThreadHelper::CreateThread(boost::bind(&A::f1, this, i, j));
32
}
33
34
HANDLE ExecuteInPool(int i, int j){
35
return ThreadHelper::QueueThread(boost::bind(&A::f1, this, i, j));
36
}
37
};
38
39
void main()
40
{
41
A a;
42
ThreadHelper::makeFlag(8, WT_EXECUTEINIOTHREAD);
43
ThreadHelper::init();
44
45
InitializeCriticalSection(&cs);
46
47
HANDLE threads[3];
48
49
threads[0] = a.ExecuteInPool(3, 4);
50
threads[1] = a.ExecuteInThread(2, 8);
51
threads[2] = ThreadHelper::QueueThread(boost::bind(&A::f1, &a, 2, 3));
52
53
WaitForMultipleObjects(3, threads, TRUE, INFINITE);
54
55
DeleteCriticalSection(&cs);
56
ThreadHelper::finalize();
57
}
58
*/
59
60
namespace LibUtil
{
61
class ThreadHelper
62

{
63
public:
64
ThreadHelper(void);
65
public:
66
~ThreadHelper(void);
67
68
typedef std::map<HANDLE, boost::any> ThreadReturnMap;
69
typedef DWORD (*ThreadProc)(LPVOID lpParameter);
70
71
static void init()
72
{
73
InitializeCriticalSection(&m_csQueueThread_Impl);
74
InitializeCriticalSection(&m_csQueueThread);
75
InitializeCriticalSection(&m_csCreateThread);
76
}
77
78
static void finalize()
79
{
80
DeleteCriticalSection(&m_csQueueThread);
81
DeleteCriticalSection(&m_csQueueThread_Impl);
82
DeleteCriticalSection(&m_csCreateThread);
83
}
84
85
static void makeFlag(int threadLimit, ULONG flagPrefix = WT_EXECUTEDEFAULT)
86
{
87
m_flagQueue = flagPrefix;
88
WT_SET_MAX_THREADPOOL_THREADS(m_flagQueue, threadLimit);
89
}
90
91
static HANDLE CreateThread(ThreadProc pFunc, LPVOID lpvThreadParam, LPSECURITY_ATTRIBUTES lpsa = NULL, DWORD cbStack = 0, DWORD fdwCreate = 0, LPDWORD lpIDThread = NULL)
92
{
93
HANDLE hThread = ::CreateThread(lpsa, cbStack, (LPTHREAD_START_ROUTINE)pFunc, lpvThreadParam, fdwCreate, lpIDThread);
94
if(hThread)
95
m_vThreads.insert(std::make_pair(hThread, boost::any()));
96
return hThread;
97
}
98
99
template <typename T>
100
static HANDLE CreateThread(T& t, LPSECURITY_ATTRIBUTES lpsa = NULL, DWORD cbStack = 0, DWORD fdwCreate = 0, LPDWORD lpIDThread = NULL)
101
{
102
EnterCriticalSection(&m_csCreateThread);
103
static std::list<boost::any> functors;
104
functors.push_back(t);
105
T* pt = &boost::any_cast<T&>(functors.back());
106
LeaveCriticalSection(&m_csCreateThread);
107
108
HANDLE hThread = CreateThread(&deliver<T>, pt, lpsa, cbStack, fdwCreate, lpIDThread);
109
if(hThread)
110
m_vThreads.insert(std::make_pair(hThread, boost::any()));
111
return hThread;
112
}
113
114
static HANDLE QueueThread(ThreadProc pFunc, LPVOID param, ULONG flag = m_flagQueue)
115
{
116
HANDLE hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
117
118
if(QueueThread_Impl(boost::bind(worker, pFunc, param, hThread), flag))
119
{
120
m_vThreads.insert(std::make_pair(hThread, boost::any()));
121
return hThread;
122
}
123
else
124
{
125
CloseHandle(hThread);
126
return NULL;
127
}
128
}
129
130
template <typename T>
131
static HANDLE QueueThread(T& t, ULONG flag = m_flagQueue)
132
{
133
EnterCriticalSection(&m_csQueueThread);
134
static std::list<boost::any> functors;
135
functors.push_back(t);
136
T* pt = &boost::any_cast<T&>(functors.back());
137
LeaveCriticalSection(&m_csQueueThread);
138
139
HANDLE hThread = CreateEvent(NULL, TRUE, FALSE, NULL);
140
141
if(QueueThread_Impl(boost::bind(&worker<T>, pt, hThread), flag))
142
{
143
m_vThreads.insert(std::make_pair(hThread, boost::any()));
144
return hThread;
145
}
146
else
147
{
148
CloseHandle(hThread);
149
return NULL;
150
}
151
}
152
153
void WaitAll(DWORD elapseTime = INFINITE)
154
{
155
std::vector<HANDLE> threads;
156
for(ThreadReturnMap::iterator it = m_vThreads.begin();
157
it != m_vThreads.end(); it ++)
158
{
159
threads.push_back(it->first);
160
}
161
WaitForMultipleObjects(threads.size(), &threads[0], TRUE, elapseTime);
162
m_vThreads.clear();
163
}
164
165
void WaitSingle(HANDLE hThread, DWORD elapseTime = INFINITE)
166
{
167
WaitForSingleObject(hThread, elapseTime);
168
169
ThreadReturnMap::iterator it = m_vThreads.find(hThread);
170
if(it != m_vThreads.end())
171
m_vThreads.erase(m_vThreads.find(hThread));
172
return;
173
}
174
175
template<typename T>
176
void WaitForReturnValue(HANDLE hThread, T& returnValue, DWORD elapseTime = INFINITE)
177
{
178
WaitForSingleObject(hThread, elapseTime);
179
180
ThreadReturnMap::iterator it = m_vThreads.find(hThread);
181
if(it != m_vThreads.end())
182
{
183
returnValue = boost::any_cast<T&>(it->second);
184
m_vThreads.erase(m_vThreads.find(hThread));
185
}
186
return;
187
}
188
189
protected:
190
191
template<typename T>
192
static bool QueueThread_Impl(T& t, ULONG flag)
193
{
194
EnterCriticalSection(&m_csQueueThread_Impl);
195
static std::list<boost::any> functors;
196
functors.push_back(t);
197
T* pt = &boost::any_cast<T&>(functors.back());
198
LeaveCriticalSection(&m_csQueueThread_Impl);
199
200
return QueueThread_Impl(&deliver<T>, pt, flag);
201
}
202
203
static bool QueueThread_Impl(ThreadProc pFunc, void* param, ULONG flag)
204
{
205
return QueueUserWorkItem((LPTHREAD_START_ROUTINE)pFunc, param, flag);
206
}
207
208
template <typename T>
209
static DWORD deliver(LPVOID p)
210
{
211
(*(T*)p)();
212
return 0;
213
}
214
215
template<typename T>
216
static void worker(T* t, HANDLE hTerminate)
217
{
218
(*t)();
219
SetEvent(hTerminate);
220
return;
221
}
222
223
static void worker(ThreadProc pFunc, LPVOID t, HANDLE hTerminate)
224
{
225
pFunc(t);
226
SetEvent(hTerminate);
227
return;
228
}
229
230
static std::map<HANDLE, boost::any> m_vThreads;
231
static ULONG m_flagQueue;
232
static CRITICAL_SECTION m_csQueueThread_Impl, m_csQueueThread, m_csCreateThread;
233
};
234
235
236
} // namespace LibUtil
237

2

3

4

5

6

7

8

9


10


11


12


13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60



61

62



63

64

65

66

67

68

69

70

71

72



73

74

75

76

77

78

79



80

81

82

83

84

85

86



87

88

89

90

91

92



93

94

95

96

97

98

99

100

101



102

103

104

105

106

107

108

109

110

111

112

113

114

115



116

117

118

119



120

121

122

123

124



125

126

127

128

129

130

131

132



133

134

135

136

137

138

139

140

141

142



143

144

145

146

147



148

149

150

151

152

153

154



155

156

157

158



159

160

161

162

163

164

165

166



167

168

169

170

171

172

173

174

175

176

177



178

179

180

181

182



183

184

185

186

187

188

189

190

191

192

193



194

195

196

197

198

199

200

201

202

203

204



205

206

207

208

209

210



211

212

213

214

215

216

217



218

219

220

221

222

223

224



225

226

227

228

229

230

231

232

233

234

235

236

237

1. boost::bind并非無限參數。一般不會超過20個。
2. 既使沒有boost::bind,std::bindxxx和std::mem_funxxx配合,也能達到同樣的效果。雖然參數不能超過2個。
3. 即使如此,自已去做一次,也有助于對C++機制的了解。
4. 如果你有需要什么功能,那么可能已經有現成的實現了。就看你是否有找到。
boost::bind的參數個數限制好像就是占位符的個數限制吧,最多9個吧,如果是類成員函數bind的話,還要再減掉一個用來傳遞依賴的對象
ps. 內容更新了
TypeList做成參數個數不限的可能性現在看來好像不存在吧,《Modern C++ Design》里就是手動寫了一個一個的宏,loki里把上限擴到50個,幾乎可以滿足所有的需求。
還是用宏算了