Mercurial > projects > ldc
comparison druntime/src/common/core/sync/mutex.d @ 1458:e0b2d67cfe7c
Added druntime (this should be removed once it works).
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Tue, 02 Jun 2009 17:43:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1456:7b218ec1044f | 1458:e0b2d67cfe7c |
---|---|
1 /** | |
2 * The mutex module provides a primitive for maintaining mutually exclusive | |
3 * access. | |
4 * | |
5 * Copyright: Copyright Sean Kelly 2005 - 2009. | |
6 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>. | |
7 * Authors: Sean Kelly | |
8 * | |
9 * Copyright Sean Kelly 2005 - 2009. | |
10 * Distributed under the Boost Software License, Version 1.0. | |
11 * (See accompanying file LICENSE_1_0.txt or copy at | |
12 * http://www.boost.org/LICENSE_1_0.txt) | |
13 */ | |
14 module core.sync.mutex; | |
15 | |
16 | |
17 public import core.sync.exception; | |
18 | |
19 version( Win32 ) | |
20 { | |
21 private import core.sys.windows.windows; | |
22 } | |
23 else version( Posix ) | |
24 { | |
25 private import core.sys.posix.pthread; | |
26 } | |
27 | |
28 | |
29 //////////////////////////////////////////////////////////////////////////////// | |
30 // Mutex | |
31 // | |
32 // void lock(); | |
33 // void unlock(); | |
34 // bool tryLock(); | |
35 //////////////////////////////////////////////////////////////////////////////// | |
36 | |
37 | |
38 /** | |
39 * This class represents a general purpose, recursive mutex. | |
40 */ | |
41 class Mutex : | |
42 Object.Monitor | |
43 { | |
44 //////////////////////////////////////////////////////////////////////////// | |
45 // Initialization | |
46 //////////////////////////////////////////////////////////////////////////// | |
47 | |
48 | |
49 /** | |
50 * Initializes a mutex object. | |
51 * | |
52 * Throws: | |
53 * SyncException on error. | |
54 */ | |
55 this() | |
56 { | |
57 version( Win32 ) | |
58 { | |
59 InitializeCriticalSection( &m_hndl ); | |
60 } | |
61 else version( Posix ) | |
62 { | |
63 int rc = pthread_mutex_init( &m_hndl, &sm_attr ); | |
64 if( rc ) | |
65 throw new SyncException( "Unable to initialize mutex" ); | |
66 } | |
67 m_proxy.link = this; | |
68 // NOTE: With DMD this can be "this.__monitor = &m_proxy". | |
69 (cast(void**) this)[1] = &m_proxy; | |
70 } | |
71 | |
72 | |
73 /** | |
74 * Initializes a mutex object and sets it as the monitor for o. | |
75 * | |
76 * In: | |
77 * o must not already have a monitor. | |
78 */ | |
79 this( Object o ) | |
80 in | |
81 { | |
82 // NOTE: With DMD this can be "o.__monitor is null". | |
83 assert( (cast(void**) o)[1] is null ); | |
84 } | |
85 body | |
86 { | |
87 this(); | |
88 // NOTE: With DMD this can be "o.__monitor = &m_proxy". | |
89 (cast(void**) o)[1] = &m_proxy; | |
90 } | |
91 | |
92 | |
93 ~this() | |
94 { | |
95 version( Win32 ) | |
96 { | |
97 DeleteCriticalSection( &m_hndl ); | |
98 } | |
99 else version( Posix ) | |
100 { | |
101 int rc = pthread_mutex_destroy( &m_hndl ); | |
102 assert( !rc, "Unable to destroy mutex" ); | |
103 } | |
104 (cast(void**) this)[1] = null; | |
105 } | |
106 | |
107 | |
108 //////////////////////////////////////////////////////////////////////////// | |
109 // General Actions | |
110 //////////////////////////////////////////////////////////////////////////// | |
111 | |
112 | |
113 /** | |
114 * If this lock is not already held by the caller, the lock is acquired, | |
115 * then the internal counter is incremented by one. | |
116 * | |
117 * Throws: | |
118 * SyncException on error. | |
119 */ | |
120 void lock() | |
121 { | |
122 version( Win32 ) | |
123 { | |
124 EnterCriticalSection( &m_hndl ); | |
125 } | |
126 else version( Posix ) | |
127 { | |
128 int rc = pthread_mutex_lock( &m_hndl ); | |
129 if( rc ) | |
130 throw new SyncException( "Unable to lock mutex" ); | |
131 } | |
132 } | |
133 | |
134 | |
135 /** | |
136 * Decrements the internal lock count by one. If this brings the count to | |
137 * zero, the lock is released. | |
138 * | |
139 * Throws: | |
140 * SyncException on error. | |
141 */ | |
142 void unlock() | |
143 { | |
144 version( Win32 ) | |
145 { | |
146 LeaveCriticalSection( &m_hndl ); | |
147 } | |
148 else version( Posix ) | |
149 { | |
150 int rc = pthread_mutex_unlock( &m_hndl ); | |
151 if( rc ) | |
152 throw new SyncException( "Unable to unlock mutex" ); | |
153 } | |
154 } | |
155 | |
156 | |
157 /** | |
158 * If the lock is held by another caller, the method returns. Otherwise, | |
159 * the lock is acquired if it is not already held, and then the internal | |
160 * counter is incremented by one. | |
161 * | |
162 * Throws: | |
163 * SyncException on error. | |
164 * | |
165 * Returns: | |
166 * true if the lock was acquired and false if not. | |
167 */ | |
168 bool tryLock() | |
169 { | |
170 version( Win32 ) | |
171 { | |
172 return TryEnterCriticalSection( &m_hndl ) != 0; | |
173 } | |
174 else version( Posix ) | |
175 { | |
176 return pthread_mutex_trylock( &m_hndl ) == 0; | |
177 } | |
178 } | |
179 | |
180 | |
181 version( Posix ) | |
182 { | |
183 static this() | |
184 { | |
185 int rc = pthread_mutexattr_init( &sm_attr ); | |
186 assert( !rc ); | |
187 | |
188 rc = pthread_mutexattr_settype( &sm_attr, PTHREAD_MUTEX_RECURSIVE ); | |
189 assert( !rc ); | |
190 } | |
191 | |
192 | |
193 static ~this() | |
194 { | |
195 int rc = pthread_mutexattr_destroy( &sm_attr ); | |
196 assert( !rc ); | |
197 } | |
198 } | |
199 | |
200 | |
201 private: | |
202 version( Win32 ) | |
203 { | |
204 CRITICAL_SECTION m_hndl; | |
205 } | |
206 else version( Posix ) | |
207 { | |
208 __gshared pthread_mutexattr_t sm_attr; | |
209 | |
210 pthread_mutex_t m_hndl; | |
211 } | |
212 | |
213 struct MonitorProxy | |
214 { | |
215 Object.Monitor link; | |
216 } | |
217 | |
218 MonitorProxy m_proxy; | |
219 | |
220 | |
221 package: | |
222 version( Posix ) | |
223 { | |
224 pthread_mutex_t* handleAddr() | |
225 { | |
226 return &m_hndl; | |
227 } | |
228 } | |
229 } | |
230 | |
231 | |
232 //////////////////////////////////////////////////////////////////////////////// | |
233 // Unit Tests | |
234 //////////////////////////////////////////////////////////////////////////////// | |
235 | |
236 | |
237 version( unittest ) | |
238 { | |
239 private import core.thread; | |
240 | |
241 | |
242 unittest | |
243 { | |
244 auto mutex = new Mutex; | |
245 int numThreads = 10; | |
246 int numTries = 1000; | |
247 int lockCount = 0; | |
248 | |
249 void testFn() | |
250 { | |
251 for( int i = 0; i < numTries; ++i ) | |
252 { | |
253 synchronized( mutex ) | |
254 { | |
255 ++lockCount; | |
256 } | |
257 } | |
258 } | |
259 | |
260 auto group = new ThreadGroup; | |
261 | |
262 for( int i = 0; i < numThreads; ++i ) | |
263 group.create( &testFn ); | |
264 | |
265 group.joinAll(); | |
266 assert( lockCount == numThreads * numTries ); | |
267 } | |
268 } |