source: trunk/ab5.0/ablib/src/Classes/System/Threading/ThreadPool.ab@ 599

Last change on this file since 599 was 599, checked in by イグトランス (egtra), 16 years ago

ThreadPoolの実装、WaitHandle.WaitAny/WaitAllのまともな実装、ほか。

File size: 7.3 KB
Line 
1'Classes/System/Threading/ThreadPool.ab
2
3Namespace System
4Namespace Threading
5Namespace Detail
6
7TypeDef PQueueUserWorkItem = *Function(fn As LPTHREAD_START_ROUTINE, context As VoidPtr, flags As DWord) As BOOL
8
9TypeDef PRegisterWaitForSingleObject = *Function(ByRef hNewWaitObject As HANDLE, hObject As HANDLE, Callback As WAITORTIMERCALLBACK, Context As VoidPtr, dwMilliseconds As DWord, dwFlags As DWord) As BOOL
10
11Const WM_QueueUserWorkItem = WM_APP + 100
12Const WM_RegisterWaitForSingleObject = WM_APP + 101
13
14Class QueueContextData<T>
15Public
16 Callback As T
17 State As Object
18
19 Sub QueueContextData(c As T, s As Object)
20 Callback = c
21 State = s
22 End Sub
23End Class
24
25Class WaitData
26Public
27 WaitObject As WaitHandle
28 Callback As WaitOrTimerCallback
29 State As Object
30
31 Sub WaitData(w As WaitHandle, c As WaitOrTimerCallback, s As Object)
32 WaitObject = w
33 Callback = c
34 State = s
35 End Sub
36End Class
37
38End Namespace
39
40Delegate Sub WaitCallback(state As Object)
41Delegate Sub WaitOrTimerCallback(state As Object, timedOut As Boolean)
42
43Class ThreadPool
44Public
45 Static Function QueueUserWorkItem(callback As WaitCallback, state = Nothing As Object) As Boolean
46 startThread()
47 Dim qcd = New Detail.QueueContextData<WaitCallback>(callback, state)
48 Dim h = ActiveBasic.AllocObjectHandle(qcd)
49 PostThreadMessage(thread.ThreadId, Detail.WM_QueueUserWorkItem, 0, h)
50 End Function
51
52 'とりあえずタイムアウト非対応
53 Static Function RegisterWaitForSingleObject(waitObject As WaitHandle, callback As WaitOrTimerCallback, state As Object) As RegisteredWaitHandle
54 startThread()
55 Dim wd = New Detail.WaitData(waitObject, callback, state)
56 Dim h = ActiveBasic.AllocObjectHandle(wd)
57 PostThreadMessage(thread.ThreadId, Detail.WM_RegisterWaitForSingleObject, 0, h)
58 End Function
59/*
60 Static Function RegisterWaitForSingleObject(waitObject As WaitHandle, callback As WaitOrTimerCallback, state As Object, millisecondsTimeOutInterval As DWord, executeOnlyOnce As Boolean) As RegisteredWaitHandle
61 End Function
62*/
63Private
64 Static Function waitCallback(param As VoidPtr) As DWord
65 Try
66 Diagnostics.Debug.Assert(param <> 0)
67 Dim qcd = ActiveBasic.ReleaseObjectHandle(param As LONG_PTR) As Detail.QueueContextData<WaitCallback>
68 With qcd
69 Diagnostics.Debug.Assert(.Callback <> 0)
70 Dim c = .Callback
71 c(.State)
72 End With
73 Catch e As Object
74 End Try
75 End Function
76
77 Static Sub waitOrTimerCallback(param As VoidPtr, TimerOrWaitFired As BOOLEAN)
78 Try
79 Diagnostics.Debug.Assert(param <> 0)
80 Dim qcd = ActiveBasic.ReleaseObjectHandle(param As LONG_PTR) As Detail.QueueContextData<WaitOrTimerCallback>
81 With qcd
82 Diagnostics.Debug.Assert(.Callback <> 0)
83 Dim c = .Callback
84 c(.State, TimerOrWaitFired)
85 End With
86 Catch e As Object
87 End Try
88 End Sub
89
90 Static Sub startThread()
91 If ActiveBasic.IsNothing(thread) Then
92 Dim lock = New ActiveBasic.Windows.CriticalSectionLock(_System_CriticalSection)
93 thread = New Thread(AddressOf(poolThread), 0)
94 thread.Name = "ThreadPool"
95 thread.Start()
96 While isMessageQueueCreated = False
97 Sleep(1)
98 Wend
99 lock.Dispose()
100 End If
101 End Sub
102
103 Static Function poolThread(pv As VoidPtr) As DWord
104 Try
105 Dim msg As MSG
106 PeekMessage(msg, 0, 0, 0, PM_NOREMOVE) 'メッセージキューの作成
107 isMessageQueueCreated = True
108 Dim waitList = New Collections.Generic.List<Detail.WaitData>
109 Dim handles = waitListToArrayOfHANDLE(waitList)
110 Do
111 While PeekMessage(msg, 0, 0, 0, PM_REMOVE)
112 Select Case msg.message
113 Case WM_QUIT
114 Exit Do
115 Case Detail.WM_QueueUserWorkItem
116 waitCallback(msg.lParam As VoidPtr)
117 Case Detail.WM_RegisterWaitForSingleObject
118 Diagnostics.Debug.Assert(msg.lParam <> 0)
119 Dim wd = ActiveBasic.ReleaseObjectHandle(msg.lParam) As Detail.WaitData
120 waitList.Add(wd)
121 handles = waitListToArrayOfHANDLE(waitList)
122 End Select
123 Wend
124 Dim retWait = MsgWaitForMultipleObjects(waitList.Count As DWord, handles, FALSE, INFINITE, QS_ALLINPUT)
125 If retWait = &hffffffff Then
126 poolThread = retWait
127 Exit Do
128 ElseIf WAIT_OBJECT_0 <= retWait And retWait < WAIT_OBJECT_0 + waitList.Count Then
129 Dim i = retWait - WAIT_OBJECT_0
130 Dim wd = waitList[i]
131 With wd
132 Dim c = wd.Callback
133 c(wd.State, False)
134 End With
135 waitList.RemoveAt(i)
136 End If
137 Loop
138 Catch e As Object
139 Diagnostics.Trace.WriteLine("ThreadPool thread catches an exception:")
140 Diagnostics.Trace.WriteLine(e.ToString)
141 End Try
142 End Function
143
144 Static Function waitListToArrayOfHANDLE(waitList As Collections.Generic.List<Detail.WaitData>) As *HANDLE
145 Diagnostics.Debug.Assert(Not ActiveBasic.IsNothing(waitList))
146 waitListToArrayOfHANDLE = GC_malloc(waitList.Count * SizeOf(HANDLE))
147 Dim count = waitList.Count
148 Dim i As Long
149 For i = 0 To ELM(count)
150 waitListToArrayOfHANDLE[i] = waitList.Item[i].WaitObject.Handle
151 Next
152 End Function
153
154 Static thread = Nothing As Thread
155 Static isMessageQueueCreated = False As Boolean
156End Class
157
158Class RegisteredWaitHandle
159End Class
160#ifdef __UNDEFINED__
161Class ThreadPool
162Public
163 Static Function QueueUserWorkItem(callback As WaitCallback, state = Nothing As Object) As Boolean
164 Dim pfn = GetProcAddress(GetModuleHandle("kernel32"), ToMBStr("QueueUserWorkItem")) As Detail.PQueueUserWorkItem
165 If pfn = 0 Then
166 'ToDo: 自前実装
167 Throw New NotSupportedException("RegisterWaitForSingleObject requires Windows 2000")
168 End If
169 Dim qcd = New Detail.QueueContextData<WaitCallback>(callback, state)
170 Dim h = ActiveBasic.AllocObjectHandle(qcd)
171 pfn(AddressOf (waitCallback), h As VoidPtr, WT_EXECUTELONGFUNCTION)
172 End Function
173
174 Static Function RegisterWaitForSingleObject(waitObject As WaitHandle, callback As WaitOrTimerCallback, state As Object, millisecondsTimeOutInterval As DWord, executeOnlyOnce As Boolean) As RegisteredWaitHandle
175 Dim pfn = GetProcAddress(GetModuleHandle("kernel32"), ToMBStr("RegisterWaitForSingleObject")) As Detail.PRegisterWaitForSingleObject
176 If pfn = 0 Then
177 'ToDo: 自前実装
178 Throw New NotSupportedException("RegisterWaitForSingleObject requires Windows 2000")
179 End If
180 Dim qcd = New Detail.QueueContextData<WaitOrTimerCallback>(callback, state)
181 Dim h = ActiveBasic.AllocObjectHandle(qcd)
182 Dim wo As HANDLE
183 pfn(wo, waitObject.Handle, 0, 0 As VoidPtr, 0, WT_EXECUTELONGFUNCTION)
184' pfn(wo, waitObject.Handle, AddressOf (waitOrTimerCallback), h As VoidPtr, millisecondsTimeOutInterval, WT_EXECUTELONGFUNCTION)
185 End Function
186
187Private
188 Static Function waitCallback(param As VoidPtr) As DWord
189 Try
190 Diagnostics.Debug.Assert(param <> 0)
191 Dim qcd = ActiveBasic.ReleaseObjectHandle(param As LONG_PTR) As Detail.QueueContextData<WaitCallback>
192 With qcd
193 Diagnostics.Debug.Assert(.Callback <> 0)
194 Dim c = .Callback
195 c(.State)
196 End With
197 Catch e As Object
198 End Try
199 End Function
200
201 Static Sub waitOrTimerCallback(param As VoidPtr, TimerOrWaitFired As BOOLEAN)
202 Try
203 Diagnostics.Debug.Assert(param <> 0)
204 Dim qcd = ActiveBasic.ReleaseObjectHandle(param As LONG_PTR) As Detail.QueueContextData<WaitOrTimerCallback>
205 With qcd
206 Diagnostics.Debug.Assert(.Callback <> 0)
207 Dim c = .Callback
208 c(.State, TimerOrWaitFired)
209 End With
210 Catch e As Object
211 End Try
212 End Sub
213End Class
214
215Class RegisteredWaitHandle
216End Class
217
218#endif
219
220End Namespace
221End Namespace
Note: See TracBrowser for help on using the repository browser.