|
20 | 20 | #ifndef THREAD_WIN32_H_INCLUDED |
21 | 21 | #define THREAD_WIN32_H_INCLUDED |
22 | 22 |
|
23 | | -/// STL thread library uded by gcc and mingw compilers is implemented above |
24 | | -/// POSIX pthread. Unfortunatly this yields to a much slower speed (about 30%) |
25 | | -/// than the native Win32 calls. So use our own implementation that relies on |
26 | | -/// the Windows specific low level calls. |
| 23 | +/// STL thread library used by mingw and gcc when cross compiling for Windows |
| 24 | +/// relies on libwinpthread. Currently libwinpthread implements mutexes directly |
| 25 | +/// on top of Windows semaphores. Semaphores, being kernel objects, require kernel |
| 26 | +/// mode transition in order to lock or unlock, which is very slow compared to |
| 27 | +/// interlocked operations (about 30% slower on bench test). To workaround this |
| 28 | +/// issue, we define our wrappers to the low level Win32 calls. We use critical |
| 29 | +/// sections to support Windows XP and older versions. Unfortunately, cond_wait() |
| 30 | +/// is racy between unlock() and WaitForSingleObject() but they have the same |
| 31 | +/// speed performance of SRW locks. |
| 32 | + |
| 33 | +#include <condition_variable> |
| 34 | +#include <mutex> |
27 | 35 |
|
28 | 36 | #if defined(_WIN32) && !defined(_MSC_VER) |
29 | 37 |
|
30 | 38 | #ifndef NOMINMAX |
31 | | -# define NOMINMAX // disable macros min() and max() |
| 39 | +# define NOMINMAX // Disable macros min() and max() |
32 | 40 | #endif |
33 | 41 |
|
34 | 42 | #define WIN32_LEAN_AND_MEAN |
35 | 43 | #include <windows.h> |
36 | 44 | #undef WIN32_LEAN_AND_MEAN |
37 | 45 | #undef NOMINMAX |
38 | 46 |
|
39 | | -// We use critical sections on Windows to support Windows XP and older versions. |
40 | | -// Unfortunately, cond_wait() is racy between lock_release() and WaitForSingleObject() |
41 | | -// but apart from this they have the same speed performance of SRW locks. |
42 | | -typedef CRITICAL_SECTION Lock; |
43 | | -typedef HANDLE WaitCondition; |
44 | | -typedef HANDLE NativeHandle; |
45 | | - |
46 | | -// On Windows 95 and 98 parameter lpThreadId may not be null |
47 | | -inline DWORD* dwWin9xKludge() { static DWORD dw; return &dw; } |
48 | | - |
49 | | -# define lock_init(x) InitializeCriticalSection(&(x)) |
50 | | -# define lock_grab(x) EnterCriticalSection(&(x)) |
51 | | -# define lock_release(x) LeaveCriticalSection(&(x)) |
52 | | -# define lock_destroy(x) DeleteCriticalSection(&(x)) |
53 | | -# define cond_init(x) { x = CreateEvent(0, FALSE, FALSE, 0); } |
54 | | -# define cond_destroy(x) CloseHandle(x) |
55 | | -# define cond_signal(x) SetEvent(x) |
56 | | -# define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); } |
57 | | -# define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); } |
58 | | - |
59 | 47 | /// Mutex and ConditionVariable struct are wrappers of the low level locking |
60 | 48 | /// machinery and are modeled after the corresponding C++11 classes. |
61 | 49 |
|
62 | 50 | struct Mutex { |
63 | | - Mutex() { lock_init(l); } |
64 | | - ~Mutex() { lock_destroy(l); } |
65 | | - |
66 | | - void lock() { lock_grab(l); } |
67 | | - void unlock() { lock_release(l); } |
| 51 | + Mutex() { InitializeCriticalSection(&cs); } |
| 52 | + ~Mutex() { DeleteCriticalSection(&cs); } |
| 53 | + void lock() { EnterCriticalSection(&cs); } |
| 54 | + void unlock() { LeaveCriticalSection(&cs); } |
68 | 55 |
|
69 | 56 | private: |
70 | | - friend struct ConditionVariable; |
71 | | - |
72 | | - Lock l; |
| 57 | + CRITICAL_SECTION cs; |
73 | 58 | }; |
74 | 59 |
|
75 | 60 | struct ConditionVariable { |
76 | | - ConditionVariable() { cond_init(c); } |
77 | | - ~ConditionVariable() { cond_destroy(c); } |
| 61 | + ConditionVariable() { hn = CreateEvent(0, FALSE, FALSE, 0); } |
| 62 | + ~ConditionVariable() { CloseHandle(hn); } |
| 63 | + void notify_one() { SetEvent(hn); } |
| 64 | + |
| 65 | + void wait(std::unique_lock<Mutex>& lk) { |
| 66 | + lk.unlock(); |
| 67 | + WaitForSingleObject(hn, INFINITE); |
| 68 | + lk.lock(); |
| 69 | + } |
78 | 70 |
|
79 | | - void notify_one() { cond_signal(c); } |
80 | | - void wait(std::unique_lock<Mutex>& lk) { cond_wait(c, lk.mutex()->l); } |
| 71 | + void wait_for(std::unique_lock<Mutex>& lk, const std::chrono::milliseconds& ms) { |
| 72 | + lk.unlock(); |
| 73 | + WaitForSingleObject(hn, ms.count()); |
| 74 | + lk.lock(); |
| 75 | + } |
81 | 76 |
|
82 | 77 | template<class Predicate> |
83 | 78 | void wait(std::unique_lock<Mutex>& lk, Predicate p) { while (!p()) this->wait(lk); } |
84 | 79 |
|
85 | | - void wait_for(std::unique_lock<Mutex>& lk, const std::chrono::milliseconds& ms) { |
86 | | - cond_timedwait(c, lk.mutex()->l, ms.count()); |
87 | | - } |
88 | | - |
89 | 80 | private: |
90 | | - WaitCondition c; |
| 81 | + HANDLE hn; |
91 | 82 | }; |
92 | 83 |
|
93 | 84 | #else // Default case: use STL classes |
|
0 commit comments