Mercurial > projects > ldc
comparison tango/tango/core/sync/Mutex.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:5825d48b27d1 | 132:1700239cab2e |
---|---|
1 /** | |
2 * The mutex module provides a primitive for maintaining mutually exclusive | |
3 * access. | |
4 * | |
5 * Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved. | |
6 * License: BSD style: $(LICENSE) | |
7 * Authors: Sean Kelly | |
8 */ | |
9 module tango.core.sync.Mutex; | |
10 | |
11 | |
12 public import tango.core.Exception : SyncException; | |
13 | |
14 version( Win32 ) | |
15 { | |
16 private import tango.sys.win32.UserGdi; | |
17 } | |
18 else version( Posix ) | |
19 { | |
20 private import tango.stdc.posix.pthread; | |
21 } | |
22 | |
23 | |
24 //////////////////////////////////////////////////////////////////////////////// | |
25 // Mutex | |
26 // | |
27 // void lock(); | |
28 // void unlock(); | |
29 // bool tryLock(); | |
30 //////////////////////////////////////////////////////////////////////////////// | |
31 | |
32 | |
33 /** | |
34 * This class represents a general purpose, recursive mutex. | |
35 */ | |
36 class Mutex : | |
37 Object.Monitor | |
38 { | |
39 //////////////////////////////////////////////////////////////////////////// | |
40 // Initialization | |
41 //////////////////////////////////////////////////////////////////////////// | |
42 | |
43 | |
44 /** | |
45 * Initializes a mutex object. | |
46 * | |
47 * Throws: | |
48 * SyncException on error. | |
49 */ | |
50 this() | |
51 { | |
52 version( Win32 ) | |
53 { | |
54 InitializeCriticalSection( &m_hndl ); | |
55 } | |
56 else version( Posix ) | |
57 { | |
58 int rc = pthread_mutex_init( &m_hndl, &sm_attr ); | |
59 if( rc ) | |
60 throw new SyncException( "Unable to initialize mutex" ); | |
61 } | |
62 m_proxy.link = this; | |
63 (cast(void**) this)[1] = &m_proxy; | |
64 } | |
65 | |
66 | |
67 ~this() | |
68 { | |
69 version( Win32 ) | |
70 { | |
71 DeleteCriticalSection( &m_hndl ); | |
72 } | |
73 else version( Posix ) | |
74 { | |
75 int rc = pthread_mutex_destroy( &m_hndl ); | |
76 assert( !rc, "Unable to destroy mutex" ); | |
77 } | |
78 (cast(void**) this)[1] = null; | |
79 } | |
80 | |
81 | |
82 //////////////////////////////////////////////////////////////////////////// | |
83 // General Actions | |
84 //////////////////////////////////////////////////////////////////////////// | |
85 | |
86 | |
87 /** | |
88 * If this lock is not already held by the caller, the lock is acquired, | |
89 * then the internal counter is incremented by one. | |
90 * | |
91 * Throws: | |
92 * SyncException on error. | |
93 */ | |
94 void lock() | |
95 { | |
96 version( Win32 ) | |
97 { | |
98 EnterCriticalSection( &m_hndl ); | |
99 } | |
100 else version( Posix ) | |
101 { | |
102 int rc = pthread_mutex_lock( &m_hndl ); | |
103 if( rc ) | |
104 throw new SyncException( "Unable to lock mutex" ); | |
105 } | |
106 } | |
107 | |
108 | |
109 /** | |
110 * Decrements the internal lock count by one. If this brings the count to | |
111 * zero, the lock is released. | |
112 * | |
113 * Throws: | |
114 * SyncException on error. | |
115 */ | |
116 void unlock() | |
117 { | |
118 version( Win32 ) | |
119 { | |
120 LeaveCriticalSection( &m_hndl ); | |
121 } | |
122 else version( Posix ) | |
123 { | |
124 int rc = pthread_mutex_unlock( &m_hndl ); | |
125 if( rc ) | |
126 throw new SyncException( "Unable to unlock mutex" ); | |
127 } | |
128 } | |
129 | |
130 | |
131 /** | |
132 * If the lock is held by another caller, the method returns. Otherwise, | |
133 * the lock is acquired if it is not already held, and then the internal | |
134 * counter is incremented by one. | |
135 * | |
136 * Returns: | |
137 * true if the lock was acquired and false if not. | |
138 * | |
139 * Throws: | |
140 * SyncException on error. | |
141 */ | |
142 bool tryLock() | |
143 { | |
144 version( Win32 ) | |
145 { | |
146 return TryEnterCriticalSection( &m_hndl ) != 0; | |
147 } | |
148 else version( Posix ) | |
149 { | |
150 return pthread_mutex_trylock( &m_hndl ) == 0; | |
151 } | |
152 } | |
153 | |
154 | |
155 version( Posix ) | |
156 { | |
157 static this() | |
158 { | |
159 int rc = pthread_mutexattr_init( &sm_attr ); | |
160 assert( !rc ); | |
161 | |
162 rc = pthread_mutexattr_settype( &sm_attr, PTHREAD_MUTEX_RECURSIVE ); | |
163 assert( !rc ); | |
164 } | |
165 | |
166 | |
167 static ~this() | |
168 { | |
169 int rc = pthread_mutexattr_destroy( &sm_attr ); | |
170 assert( !rc ); | |
171 } | |
172 } | |
173 | |
174 | |
175 private: | |
176 version( Win32 ) | |
177 { | |
178 CRITICAL_SECTION m_hndl; | |
179 } | |
180 else version( Posix ) | |
181 { | |
182 static pthread_mutexattr_t sm_attr; | |
183 | |
184 pthread_mutex_t m_hndl; | |
185 } | |
186 | |
187 struct MonitorProxy | |
188 { | |
189 Object.Monitor link; | |
190 } | |
191 | |
192 MonitorProxy m_proxy; | |
193 | |
194 | |
195 package: | |
196 version( Posix ) | |
197 { | |
198 pthread_mutex_t* handleAddr() | |
199 { | |
200 return &m_hndl; | |
201 } | |
202 } | |
203 } | |
204 | |
205 | |
206 //////////////////////////////////////////////////////////////////////////////// | |
207 // Unit Tests | |
208 //////////////////////////////////////////////////////////////////////////////// | |
209 | |
210 | |
211 debug( UnitTest ) | |
212 { | |
213 private import tango.core.Thread; | |
214 | |
215 | |
216 unittest | |
217 { | |
218 auto mutex = new Mutex; | |
219 int numThreads = 10; | |
220 int numTries = 1000; | |
221 int lockCount = 0; | |
222 | |
223 void testFn() | |
224 { | |
225 for( int i = 0; i < numTries; ++i ) | |
226 { | |
227 synchronized( mutex ) | |
228 { | |
229 ++lockCount; | |
230 } | |
231 } | |
232 } | |
233 | |
234 auto group = new ThreadGroup; | |
235 | |
236 for( int i = 0; i < numThreads; ++i ) | |
237 group.create( &testFn ); | |
238 | |
239 group.joinAll(); | |
240 assert( lockCount == numThreads * numTries ); | |
241 } | |
242 } |