7fd59977 |
1 | // File: Standard_Mutex.hxx |
2 | // Created: Mon Apr 10 12:41:43 2005 |
3 | // Author: Andrey BETENEV |
4 | // Copyright: Open CASCADE S.A.S. 2006 |
5 | |
6 | #ifndef _Standard_Mutex_HeaderFile |
7 | #define _Standard_Mutex_HeaderFile |
8 | |
9 | #include <Standard_Integer.hxx> |
10 | #include <Standard_Boolean.hxx> |
11 | #include <Standard_ErrorHandlerCallback.hxx> |
12 | |
13 | #ifdef WNT |
14 | #include <windows.h> |
15 | #else |
16 | #include <pthread.h> |
17 | #include <sys/errno.h> |
18 | #include <unistd.h> |
19 | #include <time.h> |
20 | #endif |
21 | |
22 | /** |
23 | * @brief Mutex: a class to synchronize access to shared data. |
24 | * |
25 | * This is simple encapsulation of tools provided by the |
26 | * operating system to syncronize access to shared data |
27 | * from threads within one process. |
28 | * |
29 | * Current implementation is very simple and straightforward; |
30 | * it is just a wrapper around POSIX pthread librray on UNIX/Linux, |
31 | * and CRITICAL_SECTIONs on Windows NT. It does not provide any |
32 | * advanced functionaly such as recursive calls to the same mutex from |
33 | * within one thread (such call will froze the execution). |
34 | * |
35 | * Note that all the methods of that class are made inline, in order |
36 | * to keep maximal performance. This means that a library using the mutex |
37 | * might need to be linked to threads library directly. |
38 | * |
39 | * The typical use of this class should be as follows: |
40 | * - create instance of the class Standard_Mutex in the global scope |
41 | * (whenever possible, or as a field of your class) |
42 | * - create instance of class Standard_Mutex::Sentry using that Mutex |
43 | * when entering critical section |
44 | * |
45 | * Note that this class provides one feature specific to Open CASCADE: |
46 | * safe unlocking the mutex when signal is raised and converted to OCC |
47 | * exceptions (Note that with current implementation of this functionality |
48 | * on UNIX and Linux, C longjumps are used for that, thus destructors of |
49 | * classes are not called automatically). |
50 | * |
51 | * To use this feature, call RegisterCallback() after Lock() or successful |
52 | * TryLock(), and UnregisterCallback() before Unlock() (or use Sentry classes). |
53 | */ |
54 | |
55 | class Standard_Mutex : public Standard_ErrorHandlerCallback |
56 | { |
57 | public: |
58 | /** |
59 | * @brief Simple sentry class providing convenient interface to mutex. |
60 | * |
61 | * Provides automatic locking and unlocking a mutex in its constructor |
62 | * and destructor, thus ensuring correct unlock of the mutex even in case of |
63 | * raising an exception or signal from the protected code. |
64 | * |
65 | * Create instance of that class when entering critical section. |
66 | */ |
67 | class Sentry |
68 | { |
69 | public: |
70 | |
71 | //! Constructor - initializes the sentry object by reference to a |
72 | //! mutex (which must be initialized) and locks the mutex immediately |
73 | Sentry (Standard_Mutex &theMutex) |
74 | : myMutex(theMutex) |
75 | { |
76 | myMutex.Lock(); |
77 | myMutex.RegisterCallback(); |
78 | } |
79 | |
80 | //! Destructor - unlocks the mutex if already locked. |
81 | ~Sentry () { |
82 | myMutex.UnregisterCallback(); |
83 | myMutex.Unlock(); |
84 | } |
85 | |
86 | |
87 | private: |
88 | //! This method should not be called (prohibited). |
89 | Sentry (const Sentry &); |
90 | //! This method should not be called (prohibited). |
91 | Sentry& operator = (const Sentry &); |
92 | |
93 | private: |
94 | Standard_Mutex &myMutex; |
95 | }; |
96 | |
97 | /** |
98 | * @brief Advanced Sentry class providing convenient interface to |
99 | * manipulate a mutex from one thread. |
100 | * |
101 | * As compared with simple Sentry class, provides possibility to |
102 | * lock and unlock mutex at any moment, and perform nested lock/unlock |
103 | * actions (using lock counter). However all calls must be from within |
104 | * the same thread; this is to be ensured by the code using this class. |
105 | */ |
106 | class SentryNested |
107 | { |
108 | public: |
109 | |
110 | //! Constructor - initializes the sentry object by reference to a |
111 | //! mutex (which must be initialized). Locks the mutex immediately |
112 | //! unless Standard_False is given as second argument. |
113 | SentryNested (Standard_Mutex &theMutex, Standard_Boolean doLock = Standard_True) |
114 | : myMutex(theMutex), nbLocked(0) |
115 | { |
116 | if ( doLock ) Lock(); |
117 | } |
118 | |
119 | //! Destructor - unlocks the mutex if already locked. |
120 | ~SentryNested () |
121 | { |
122 | if ( nbLocked >0 ) { |
123 | nbLocked = 1; |
124 | Unlock(); |
125 | } |
126 | } |
127 | |
128 | //! Lock the mutex |
129 | void Lock () { |
130 | if ( ! nbLocked ) { |
131 | myMutex.Lock(); |
132 | myMutex.RegisterCallback(); |
133 | } |
134 | nbLocked++; |
135 | } |
136 | |
137 | //! Unlock the mutex |
138 | void Unlock () { |
139 | if ( nbLocked == 1 ) { |
140 | myMutex.UnregisterCallback(); |
141 | myMutex.Unlock(); |
142 | } |
143 | nbLocked--; |
144 | } |
145 | |
146 | private: |
147 | //! This method should not be called (prohibited). |
148 | SentryNested (const SentryNested &); |
149 | //! This method should not be called (prohibited). |
150 | SentryNested& operator = (const SentryNested &); |
151 | |
152 | private: |
153 | Standard_Mutex &myMutex; |
154 | Standard_Boolean nbLocked; //!< Note that we do not protect this field from |
155 | //!< concurrent access, as it should always be accessed |
156 | //!< from within one thread, i.e. synchronously |
157 | }; |
158 | |
159 | public: |
160 | |
161 | //! Constructor: creates a mutex object and initializes it. |
162 | //! It is strongly recommended that mutexes were created as |
163 | //! static objects whenever possible. |
164 | Standard_EXPORT Standard_Mutex (); |
165 | |
166 | //! Destructor: destroys the mutex object |
167 | Standard_EXPORT ~Standard_Mutex (); |
168 | |
169 | //! Method to lock the mutex; waits until the mutex is released |
170 | //! by other threads, locks it and then returns |
171 | Standard_EXPORT void Lock (); |
172 | |
173 | //! Method to test the mutex; if the mutex is not hold by other thread, |
174 | //! locks it and returns True; otherwise returns False without waiting |
175 | //! mutex to be released. |
176 | Standard_EXPORT Standard_Boolean TryLock (); |
177 | |
178 | //! Method to unlock the mutex; releases it to other users |
179 | Standard_EXPORT void Unlock (); |
180 | |
181 | private: |
182 | |
183 | //! Callback method to unlock the mutex if OCC exception or signal is raised |
184 | virtual void DestroyCallback (); |
185 | |
186 | private: |
187 | #ifdef WNT |
188 | CRITICAL_SECTION myMutex; |
189 | #else |
190 | pthread_mutex_t myMutex; |
191 | #endif |
192 | }; |
193 | |
194 | // Implementation of the method Unlock is inline, since it is |
195 | // just a shortcut to system function |
196 | inline void Standard_Mutex::Unlock () |
197 | { |
198 | #ifdef WNT |
199 | LeaveCriticalSection( &myMutex ); |
200 | #else |
201 | pthread_mutex_unlock( &myMutex ); |
202 | #endif |
203 | } |
204 | |
205 | #endif /* _Standard_Mutex_HeaderFile */ |