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 }