Integration of OCCT 6.5.0 from SVN
[occt.git] / src / Standard / Standard_Mutex.hxx
CommitLineData
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
55class Standard_Mutex : public Standard_ErrorHandlerCallback
56{
57public:
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
159public:
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
181private:
182
183 //! Callback method to unlock the mutex if OCC exception or signal is raised
184 virtual void DestroyCallback ();
185
186private:
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
196inline 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 */