Teh first one
[mldemos:kalians-mldemos.git] / _AlgorithmsPlugins / KernelMethods / dlib / threads / threads_kernel_1.h
1 // Copyright (C) 2003  Davis E. King (davis@dlib.net)\r
2 // License: Boost Software License   See LICENSE.txt for the full license.\r
3 #ifndef DLIB_THREADS_KERNEl_1_\r
4 #define DLIB_THREADS_KERNEl_1_\r
5 \r
6 #ifdef DLIB_ISO_CPP_ONLY\r
7 #error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it."\r
8 #endif\r
9 \r
10 #include "threads_kernel_abstract.h"\r
11 \r
12 #include "../windows_magic.h"\r
13 #include <windows.h>\r
14 #include "../algs.h"\r
15 \r
16 \r
17 namespace dlib\r
18 {\r
19 \r
20 // ----------------------------------------------------------------------------------------\r
21     \r
22     typedef DWORD thread_id_type;\r
23 \r
24     inline thread_id_type get_thread_id (\r
25     )\r
26     {\r
27         return GetCurrentThreadId();\r
28     }\r
29 \r
30 // ----------------------------------------------------------------------------------------\r
31 // ----------------------------------------------------------------------------------------\r
32     // mutex object\r
33 // ----------------------------------------------------------------------------------------\r
34 // ----------------------------------------------------------------------------------------\r
35 \r
36     // forward declaration of signaler\r
37     class signaler;\r
38 \r
39     class mutex\r
40     {\r
41         // give signaler access to hMutex\r
42         friend class signaler;\r
43     public:\r
44 \r
45         mutex (\r
46         ) :\r
47             hMutex(CreateMutex(NULL,FALSE,NULL))\r
48         {\r
49             if (hMutex == NULL)\r
50             {\r
51                 throw dlib::thread_error(ECREATE_MUTEX,\r
52         "in function mutex::mutex() an error occurred making the mutex"\r
53                 );           \r
54             }\r
55         }\r
56 \r
57         ~mutex (\r
58         ) { CloseHandle(hMutex); }\r
59 \r
60         void lock (\r
61         ) const { WaitForSingleObject (hMutex,INFINITE); }\r
62 \r
63         void unlock (\r
64         ) const { ReleaseMutex(hMutex); }\r
65 \r
66     private:\r
67 \r
68         mutable HANDLE hMutex;\r
69 \r
70         // restricted functions\r
71         mutex(mutex&);        // copy constructor\r
72         mutex& operator=(mutex&);    // assignment operator\r
73     };\r
74 \r
75 // ----------------------------------------------------------------------------------------\r
76 // ----------------------------------------------------------------------------------------\r
77     // signaler object\r
78 // ----------------------------------------------------------------------------------------\r
79 // ----------------------------------------------------------------------------------------\r
80 \r
81     class signaler\r
82     {\r
83 \r
84     public:\r
85         signaler (\r
86             const mutex& associated_mutex\r
87         ) :\r
88             hSemaphore(CreateSemaphore (NULL, 0, 100000000, NULL)),\r
89             waiters(0),\r
90             hWaitersMutex(CreateMutex(NULL,FALSE,NULL)),\r
91             hCountSema(CreateSemaphore (NULL,0,100000000,NULL)),\r
92             m(associated_mutex)\r
93         {           \r
94             if (hSemaphore == NULL || hWaitersMutex == NULL || hCountSema == NULL)\r
95             {\r
96                 if (hSemaphore != NULL)\r
97                 {\r
98                     CloseHandle(hSemaphore); \r
99                 }\r
100 \r
101                 if (hWaitersMutex != NULL)\r
102                 {\r
103                     CloseHandle(hWaitersMutex); \r
104                 }\r
105 \r
106                 if (hCountSema != NULL)\r
107                 {\r
108                     CloseHandle(hCountSema); \r
109                 }\r
110 \r
111                 throw dlib::thread_error(ECREATE_SIGNALER,\r
112         "in function signaler::signaler() an error occurred making the signaler"\r
113                 );        \r
114             }\r
115         }\r
116 \r
117         ~signaler (\r
118         ) { CloseHandle(hSemaphore); CloseHandle(hWaitersMutex); CloseHandle(hCountSema);}\r
119 \r
120         void wait (\r
121         ) const\r
122         { \r
123             // get a lock on the mutex for the waiters variable\r
124             WaitForSingleObject (hWaitersMutex,INFINITE);\r
125             // mark that one more thread will be waiting on this signaler\r
126             ++waiters;\r
127             // release the mutex for waiters\r
128             ReleaseMutex(hWaitersMutex);\r
129 \r
130             // release the assocaited mutex\r
131             ReleaseMutex(m.hMutex);\r
132 \r
133             // wait for the semaphore to be signaled\r
134             WaitForSingleObject (hSemaphore,INFINITE);\r
135 \r
136             // signal that we are awake\r
137             ReleaseSemaphore(hCountSema,(LONG)1,NULL);\r
138 \r
139             // relock the associated mutex \r
140             WaitForSingleObject (m.hMutex,INFINITE);  \r
141         }\r
142 \r
143         bool wait_or_timeout (\r
144             unsigned long milliseconds\r
145         ) const\r
146         { \r
147             // get a lock on the mutex for the waiters variable\r
148             WaitForSingleObject (hWaitersMutex,INFINITE);\r
149             // mark that one more thread will be waiting on this signaler\r
150             ++waiters;\r
151             // release the mutex for waiters\r
152             ReleaseMutex(hWaitersMutex);\r
153 \r
154             // release the assocaited mutex\r
155             ReleaseMutex(m.hMutex);\r
156 \r
157             bool value;\r
158 \r
159             // wait for the semaphore to be signaled\r
160             if ( WaitForSingleObject (hSemaphore, milliseconds ) == WAIT_TIMEOUT )\r
161             {\r
162                 // in this case we should decrement waiters because we are returning\r
163                 // due to a timeout rather than because someone called signal() or \r
164                 // broadcast().\r
165                 value = false;\r
166 \r
167                 // get a lock on the mutex for the waiters variable\r
168                 WaitForSingleObject (hWaitersMutex,INFINITE);\r
169                 // mark that one less thread will be waiting on this signaler. \r
170                 if (waiters != 0)\r
171                     --waiters;\r
172                 // release the mutex for waiters\r
173                 ReleaseMutex(hWaitersMutex);\r
174             }\r
175             else \r
176             {\r
177                 value = true;\r
178             }\r
179 \r
180             // signal that we are awake\r
181             ReleaseSemaphore(hCountSema,(LONG)1,NULL);\r
182 \r
183             // relock the associated mutex \r
184             WaitForSingleObject (m.hMutex,INFINITE);  \r
185 \r
186             return value;\r
187         }\r
188 \r
189         void signal (\r
190         ) const \r
191         { \r
192             // get a lock on the mutex for the waiters variable\r
193             WaitForSingleObject (hWaitersMutex,INFINITE);\r
194             \r
195             if (waiters > 0)\r
196             {\r
197                 --waiters;\r
198                 // make the semaphore release one waiting thread\r
199                 ReleaseSemaphore(hSemaphore,1,NULL);\r
200 \r
201                 // wait for signaled thread to wake up\r
202                 WaitForSingleObject(hCountSema,INFINITE);               \r
203             }\r
204 \r
205             // release the mutex for waiters\r
206             ReleaseMutex(hWaitersMutex);             \r
207         }\r
208 \r
209         void broadcast (\r
210         ) const \r
211         { \r
212             // get a lock on the mutex for the waiters variable\r
213             WaitForSingleObject (hWaitersMutex,INFINITE);\r
214             \r
215             if (waiters > 0)\r
216             {   \r
217                 // make the semaphore release all the waiting threads\r
218                 ReleaseSemaphore(hSemaphore,(LONG)waiters,NULL);\r
219 \r
220                 // wait for count to be zero\r
221                 for (unsigned long i = 0; i < waiters; ++i)\r
222                 {\r
223                     WaitForSingleObject(hCountSema,INFINITE);\r
224                 }\r
225 \r
226                 waiters = 0;\r
227             }\r
228 \r
229             // release the mutex for waiters\r
230             ReleaseMutex(hWaitersMutex);               \r
231         }\r
232 \r
233         const mutex& get_mutex (\r
234         ) const { return m; }\r
235 \r
236     private:\r
237 \r
238         mutable HANDLE hSemaphore;\r
239 \r
240         mutable unsigned long waiters;\r
241         mutable HANDLE hWaitersMutex;\r
242         \r
243 \r
244         mutable HANDLE hCountSema;\r
245 \r
246         const mutex& m;\r
247 \r
248         // restricted functions\r
249         signaler(signaler&);        // copy constructor\r
250         signaler& operator=(signaler&);    // assignment operator\r
251     };\r
252 \r
253 // ----------------------------------------------------------------------------------------\r
254 \r
255     namespace threads_kernel_shared_helpers\r
256     {\r
257         bool spawn_thread (\r
258             void (*funct)(void*),\r
259             void* param\r
260         );\r
261         /*!\r
262             is identical to create_new_thread() but just doesn't use any thread pooling.\r
263         !*/\r
264     }\r
265 \r
266 // ----------------------------------------------------------------------------------------\r
267 \r
268 }\r
269 \r
270 #include "threads_kernel_shared.h"\r
271 \r
272 #ifdef NO_MAKEFILE\r
273 #include "threads_kernel_1.cpp"\r
274 #endif\r
275 \r
276 #endif // DLIB_THREADS_KERNEl_1_\r
277 \r