c++-gtk-utils
rw_lock.h
Go to the documentation of this file.
1 /* Copyright (C) 2010 to 2013 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 #ifndef CGU_RW_LOCK_H
40 #define CGU_RW_LOCK_H
41 
42 #include <exception>
43 #include <pthread.h>
44 
45 #include <c++-gtk-utils/mutex.h> // for Locked and DeferLock enumerations
47 
48 /**
49  * @file rw_lock.h
50  * @brief Provides wrapper class for pthread read-write locks, and
51  * scoped locking classes for exception safe locking of read-write
52  * locks.
53  */
54 
55 namespace Cgu {
56 
57 namespace Thread {
58 
59 struct RWLockError: public std::exception {
60  virtual const char* what() const throw() {return "Thread::RWLockError";}
61 };
62 
63 /**
64  * @class RWLock rw_lock.h c++-gtk-utils/rw_lock.h
65  * @brief A wrapper class for pthread read-write locks.
66  * @sa Thread::Thread Thread::RWLock::ReaderLock Thread::RWLock::ReaderTrackLock Thread::RWLock::WriterLock Thread::RWLock::WriterTrackLock Thread::Mutex
67  *
68  * This class can be used interchangeably with threads started with
69  * GThread and by this library, as both glib and this library use
70  * pthreads underneath on POSIX and other unix-like OSes. RWLock
71  * objects can be constructed statically as well as dynamically and
72  * there is no need to call g_thread_init() before they are
73  * constructed, even if glib < 2.32 is used. (If created as a static
74  * object in global scope, it will not be possible to catch
75  * Thread::RWLockError thrown by its constructor, but if a static
76  * global read-write lock throws there is nothing that could be done
77  * anyway except abort, and it would show that the pthreads
78  * installation is seriously defective.)
79  *
80  * Read-write locks are similar to mutexes except that they allow more
81  * than one thread to hold the lock for reading at once. This can
82  * offer advantages over a mutex where a particular shared object is
83  * thread safe for lock-free reading by multiple threads
84  * simultaneously, is frequently read by different threads and is not
85  * often modified. However, the implementation of a read-write lock
86  * is more complex than that of a mutex, and unless the particular
87  * pthread read-write lock scheduling implementation favours
88  * already-blocking writers over later readers whenever a read-write
89  * lock object is unlocked, writer starvation can occur. Unless all
90  * the reads are of significant duration, might cause (if protected by
91  * a mutex) significant contention between each other and greatly
92  * exceed the number of times the write lock is held, then it is
93  * usually better to use an ordinary mutex.
94  */
95 
96 class RWLock {
97  pthread_rwlock_t pthr_rwlock;
98 
99  // read-write locks cannot be copied
100  RWLock(const RWLock&);
101  RWLock& operator=(const RWLock&);
102 public:
103  class ReaderLock;
104  class ReaderTrackLock;
105  class WriterLock;
106  class WriterTrackLock;
107 
108 /**
109  * Locks the read-write lock for reading. Blocks if already locked
110  * for writing until it becomes free. More than one thread may
111  * simultaneously hold a read lock, and a thread may lock for reading
112  * recursively provided that each call to this method is matched by a
113  * call to unlock(). It is not a cancellation point. It does not
114  * throw. It is thread safe.
115  * @return 0 if successful, otherwise the pthread read-write lock
116  * error number.
117  * @note With this library implementation, the only pthread error
118  * numbers which could be returned by this method are EDEADLK and
119  * EAGAIN. EDEADLK would be returned if the default pthread reader
120  * lock behaviour happens to return that error rather than deadlock
121  * where the thread calling this method already holds a write lock on
122  * this read-write lock. Most default implementations do not do this
123  * (they just deadlock) and hence the return value is usually not
124  * worth checking for except during debugging. EAGAIN would be
125  * returned if the maximum number of read locks for this read-write
126  * lock has been reached. Usually this number is at or around INT_MAX
127  * so it is also not usually useful to check for it except during
128  * debugging.
129  *
130  * Since 1.2.1
131  */
132  int reader_lock() {return pthread_rwlock_rdlock(&pthr_rwlock);}
133 
134 /**
135  * Tries to lock the read-write lock for reading, but returns
136  * immediately with value EBUSY if it is already locked for writing.
137  * More than one thread may simultaneously hold a read lock, and a
138  * thread may lock for reading recursively provided that each
139  * successful call to this method is matched by a call to unlock().
140  * It is not a cancellation point. It does not throw. It is thread
141  * safe.
142  * @return 0 if successful, otherwise EBUSY or other pthread
143  * read-write lock error number.
144  * @note With this library implementation, apart from EBUSY, the only
145  * other pthread error number which could be returned by this method
146  * is EAGAIN, which would be returned if the maximum number of read
147  * locks for this read-write lock has been reached. Usually this
148  * number is at or around INT_MAX so it is not usually useful to check
149  * for it except during debugging.
150  *
151  * Since 1.2.1
152  */
153  int reader_trylock() {return pthread_rwlock_tryrdlock(&pthr_rwlock);}
154 
155 /**
156  * Locks the read-write lock for writing and acquires ownership.
157  * Blocks if already locked for reading or writing until it becomes
158  * free. It is not a cancellation point. It does not throw. It is
159  * thread safe.
160  * @return 0 if successful, otherwise the pthread read-write lock
161  * error number.
162  * @note With this library implementation, the only pthread error
163  * number which could be returned by this method is EDEADLK, which it
164  * would do if the default pthread reader lock behaviour happens to
165  * return that error rather than deadlock where the thread calling
166  * this method already holds a read lock or write lock on this
167  * read-write lock. Most default implementations do not do this (they
168  * just deadlock) and hence the return value is usually not worth
169  * checking for except during debugging.
170  *
171  * Since 1.2.1
172  */
173  int writer_lock() {return pthread_rwlock_wrlock(&pthr_rwlock);}
174 
175 /**
176  * Tries to lock the read-write lock for writing and acquire
177  * ownership, but returns immediately with value EBUSY if it is
178  * already locked for reading or writing. It is not a cancellation
179  * point. It does not throw. It is thread safe.
180  * @return 0 if successful, otherwise EBUSY.
181  * @note With this library implementation, the only pthread error
182  * number which could be returned by this method is EBUSY.
183  *
184  * Since 1.2.1
185  */
186  int writer_trylock() {return pthread_rwlock_trywrlock(&pthr_rwlock);}
187 
188 /**
189  * Unlocks a read-write lock previously locked for reading or writing
190  * by the calling thread. If the calling thread has locked the
191  * read-write lock for writing, it relinquishes ownership. If it has
192  * previously locked the read-write lock for reading, it releases that
193  * particular lock, but the read-write lock may remain locked for
194  * reading if it has been locked for reading recursively or other
195  * threads hold a read lock and the particular implementation does not
196  * provide writer priority. It is not a cancellation point. It does
197  * not throw.
198  * @return 0 if successful, otherwise the pthread read-write lock
199  * error number.
200  * @note With this library implementation, the only pthread error
201  * number which could be returned by this method is EPERM because the
202  * calling thread does hold a lock on this read-write lock (however
203  * POSIX does not require that return value in that case and hence the
204  * return value is usually not worth checking for except during
205  * debugging).
206  *
207  * Since 1.2.1
208  */
209  int unlock() {return pthread_rwlock_unlock(&pthr_rwlock);}
210 
211 /**
212  * Initialises the pthread read-write lock. It is not a cancellation
213  * point.
214  * @exception Cgu::Thread::RWLockError Throws this exception if
215  * initialisation of the read-write lock fails. (It is often not
216  * worth checking for this, as it means either memory is exhausted or
217  * pthread has run out of other resources to create new read-write
218  * locks.)
219  *
220  * Since 1.2.1
221  */
222  RWLock() {if (pthread_rwlock_init(&pthr_rwlock, 0)) throw RWLockError();}
223 
224 /**
225  * Destroys the pthread read-write lock. It is not a cancellation
226  * point. It does not throw.
227  *
228  * Since 1.2.1
229  */
230  ~RWLock() {pthread_rwlock_destroy(&pthr_rwlock);}
231 
232 /* Only has effect if --with-glib-memory-slices-compat or
233  * --with-glib-memory-slices-no-compat option picked */
235 };
236 
237 /**
238  * @class RWLock::ReaderLock rw_lock.h c++-gtk-utils/rw_lock.h
239  * @brief A scoped locking class for exception safe RWLock read locking.
240  * @sa Thread::RWLock Thread::RWLock::ReaderTrackLock Thread::RWLock::WriterLock Thread::RWLock::WriterTrackLock Thread::Thread
241  */
242 
244  RWLock& rw_lock;
245 
246  // locks cannot be copied
248  RWLock::ReaderLock& operator=(const RWLock::ReaderLock&);
249 public:
250 
251 /**
252  * Calls RWLock::reader_lock(), and so relocks the read-write lock for
253  * reading. It blocks if the read-write lock is already locked for
254  * writing until it becomes free. This method should normally only be
255  * called if a previous call has been made to
256  * RWLock::ReaderLock::unlock() (that is, where the thread owning the
257  * RWLock::ReaderLock object has temporarily allowed another thread to
258  * take the read-write lock concerned for writing if another thread
259  * does not hold a read lock or the read-write lock has not been
260  * recursively locked for reading). It is not a cancellation point.
261  * It does not throw.
262  * @return 0 if successful, otherwise the pthread read-write lock
263  * error number.
264  * @note With this library implementation, the only pthread error
265  * numbers which could be returned by this method are EDEADLK and
266  * EAGAIN. EDEADLK would be returned if the default pthread reader
267  * lock behaviour happens to return that error rather than deadlock
268  * where the thread calling this method already holds a write lock on
269  * the particular read-write lock in question. Most default
270  * implementations do not do this (they just deadlock) and hence the
271  * return value is usually not worth checking for except during
272  * debugging. EAGAIN would be returned if the maximum number of read
273  * locks for the read-write lock in question has been reached.
274  * Usually this number is at or around INT_MAX so it is also not
275  * usually useful to check for it except during debugging.
276  * @sa RWLock::ReaderTrackLock
277  *
278  * Since 1.2.1
279  */
280  int lock() {return rw_lock.reader_lock();}
281 
282 /**
283  * Calls RWLock::reader_trylock(), and so tries to relock the
284  * read-write lock for reading, but returns immediately with value
285  * EBUSY if it is already locked for writing. This method should
286  * normally only be called if a previous call has been made to
287  * RWLock::ReaderLock::unlock() (that is, where the thread owning the
288  * RWLock::ReaderLock object has temporarily allowed another thread to
289  * take the read-write lock concerned for writing if another thread
290  * does not hold a read lock or the read-write lock has not been
291  * recursively locked for reading). It is not a cancellation point.
292  * It does not throw.
293  * @return 0 if successful, otherwise EBUSY or other pthread
294  * read-write lock error number.
295  * @note With this library implementation, apart from EBUSY, the only
296  * other pthread error number which could be returned by this method
297  * is EAGAIN, which would be returned if the maximum number of read
298  * locks for the particular read-write lock in question has been
299  * reached. Usually this number is at or around INT_MAX so it is not
300  * usually useful to check for it except during debugging.
301  * @sa RWLock::ReaderTrackLock
302  *
303  * Since 1.2.1
304  */
305  int trylock() {return rw_lock.reader_trylock();}
306 
307 /**
308  * Calls RWLock::unlock(), and so unlocks a locked read-write lock
309  * held by the calling thread for reading (so temporarily allowing
310  * another thread to take the read-write lock for writing should no
311  * other read lock be held or the particular implementation provides
312  * writer priority). This method should normally only be called if it
313  * is to be followed by a call to RWLock::ReaderLock::lock() or a
314  * successful call to RWLock::ReaderLock::trylock() before the
315  * RWLock::ReaderLock object concerned goes out of scope (otherwise
316  * RWLock::ReaderLock's destructor will attempt to unlock an already
317  * unlocked read-write lock or a read-write lock of which another
318  * thread holds a lock - RWLock::ReaderLock objects do not maintain
319  * state). See RWLock::ReaderTrackLock::unlock() for a safe version
320  * of this method. It is not a cancellation point. It does not
321  * throw.
322  * @return 0 if successful, otherwise the pthread read-write lock
323  * error number.
324  * @note With this library implementation, the only pthread error
325  * number which could be returned by this method is EPERM because the
326  * calling thread does hold a lock on the particular read-write lock
327  * in question (however POSIX does not require that return value in
328  * that case and hence the return value is usually not worth checking
329  * for except during debugging).
330  * @sa RWLock::ReaderTrackLock
331  *
332  * Since 1.2.1
333  */
334  int unlock() {return rw_lock.unlock();}
335 
336 /**
337  * This constructor locks for reading the read-write lock passed to
338  * it. It is not a cancellation point.
339  * @param rw_lock_ The read-write lock to be locked for reading.
340  * @exception Cgu::Thread::RWLockError Throws this exception if
341  * initialization of the read-write lock fails because the maximum
342  * number of read locks for the particular read-write lock in question
343  * has been reached. Usually this number is at or around INT_MAX so
344  * it is not usually useful to check for the exception except during
345  * debugging. This exception may also be thrown if the thread
346  * constructing this object already holds a write lock on the
347  * read-write lock in question. It will do this if the default pthread
348  * implementation returns EDEADLK in such a case instead of
349  * deadlocking. However as most default implementations will simply
350  * deadlock in such circumstances, it is usually not worth checking
351  * for this either except during debugging.
352  *
353  * Since 1.2.1
354  */
355  ReaderLock(RWLock& rw_lock_): rw_lock(rw_lock_) {if (rw_lock.reader_lock()) throw RWLockError();}
356 
357 /**
358  * This constructor takes a read-write lock already locked for reading
359  * (say as a result of RWLock::reader_trylock()), and takes management
360  * of that read lock operation. It is not a cancellation point. It
361  * does not throw.
362  * @param rw_lock_ The read-write lock to be managed for reading by
363  * this object.
364  * @param tag Pass the Cgu::Thread::locked enum tag to this parameter.
365  *
366  * Since 1.2.1
367  */
368  ReaderLock(RWLock& rw_lock_, Locked tag): rw_lock(rw_lock_) {}
369 
370 /**
371  * The destructor unlocks the read-write lock which is managed for
372  * reading. It is not a cancellation point. It does not throw.
373  *
374  * Since 1.2.1
375  */
376  ~ReaderLock() {rw_lock.unlock();}
377 
378 /* Only has effect if --with-glib-memory-slices-compat or
379  * --with-glib-memory-slices-no-compat option picked */
381 };
382 
383 /**
384  * @class RWLock::ReaderTrackLock rw_lock.h c++-gtk-utils/rw_lock.h
385  * @brief A scoped locking class for exception safe RWLock read
386  * locking which tracks the status of its read-write lock.
387  * @sa Thread::RWLock Thread::RWLock::ReaderLock Thread::RWLock::WriterLock Thread::RWLock::WriterTrackLock Thread::Thread
388  *
389  * This class is similar to a RWLock::ReaderLock object, except that
390  * it tracks whether the read-write lock it manages is locked for
391  * reading by the thread creating the RWLock::ReaderTrackLock object
392  * with respect to the particular read-locking operation to be
393  * governed by the object (provided that, while the
394  * RWLock::ReaderTrackLock object exists, the thread creating it only
395  * accesses the managed read-write lock with respect that particular
396  * operation through that object). This enables
397  * RWLock::ReaderTrackLock::unlock() to be used without it being
398  * followed later by a call to RWLock::ReaderTrackLock::lock() or a
399  * successful call to RWLock::ReaderTrackLock::trylock(), and also
400  * permits locking to be deferred until after construction of the
401  * RWLock::ReaderTrackLock object. Note that only one thread may call
402  * the methods of any one RWLock::ReaderTrackLock object, including
403  * causing its destructor to be invoked.
404  */
405 
407  RWLock& rw_lock;
408  bool owner;
409 
410  // locks cannot be copied
413 public:
414 
415 /**
416  * This calls RWLock::reader_lock(), and so locks the read-write lock
417  * for reading and acquires ownership (which may be shared with other
418  * read locks). It blocks if the read-write lock is already locked
419  * for writing until it becomes free. This method should normally
420  * only be called if a previous call has been made to
421  * RWLock::ReaderTrackLock::unlock() or this RWLock::ReaderTrackLock
422  * object has been constructed with the Thread::defer enum tag. It is
423  * not a cancellation point. It does not throw.
424  * @return 0 if successful, otherwise the pthread read-write lock
425  * error number.
426  * @note With this library implementation, the only pthread error
427  * numbers which could be returned by this method are EDEADLK and
428  * EAGAIN. EDEADLK would be returned if the default pthread reader
429  * lock behaviour happens to return that error rather than deadlock
430  * where the thread calling this method already holds a write lock on
431  * the particular read-write lock in question. Most default
432  * implementations do not do this (they just deadlock) and hence the
433  * return value is usually not worth checking for except during
434  * debugging. EAGAIN would be returned if the maximum number of read
435  * locks for the read-write lock in question has been reached.
436  * Usually this number is at or around INT_MAX so it is also not
437  * usually useful to check for it except during debugging.
438  *
439  * Since 1.2.1
440  */
441  int lock() {int ret = rw_lock.reader_lock(); if (!owner) owner = !ret; return ret;}
442 
443 /**
444  * This calls RWLock::reader_trylock(), and so tries to lock the
445  * read-write lock for reading and acquire ownership (which may be
446  * shared with other read locks), but returns immediately with value
447  * EBUSY if it is already locked for writing. This method should
448  * normally only be called if a previous call has been made to
449  * RWLock::ReaderTrackLock::unlock() or this RWLock::ReaderTrackLock
450  * object has been constructed with the Thread::defer enum tag. It is
451  * not a cancellation point. It does not throw.
452  * @return 0 if successful, otherwise EBUSY or other pthread
453  * read-write lock error number.
454  * @note With this library implementation, apart from EBUSY, the only
455  * other pthread error number which could be returned by this method
456  * is EAGAIN, which would be returned if the maximum number of read
457  * locks for the particular read-write lock in question has been
458  * reached. Usually this number is at or around INT_MAX so it is not
459  * usually useful to check for it except during debugging.
460  *
461  * Since 1.2.1
462  */
463  int trylock() {int ret = rw_lock.reader_trylock(); if (!owner) owner = !ret; return ret;}
464 
465 /**
466  * This calls RWLock::unlock(), and so unlocks a locked read-write
467  * lock held by the calling thread for reading and relinquishes
468  * ownership (whether it was sole or shared with other read locks).
469  * It will cause is_owner() to return false unless a subsequent call
470  * is made to lock() or a subsequent successful call is made to
471  * trylock(). It is not a cancellation point. It does not throw.
472  * @return 0 if successful, otherwise the pthread read-write lock
473  * error number.
474  * @note With this library implementation, the only pthread error
475  * number which could be returned by this method is EPERM because the
476  * calling thread does hold a lock on the particular read-write lock
477  * in question (however POSIX does not require that return value in
478  * that case and hence the return value is usually not worth checking
479  * for except during debugging).
480  *
481  * Since 1.2.1
482  */
483  int unlock() {int ret = rw_lock.unlock(); if (owner) owner = ret; return ret;}
484 
485 /**
486  * Indicates whether the read-write lock managed by this
487  * RWLock::ReaderTrackLock object is locked for reading by it and so
488  * owned by it (whether solely or with other read locks). It does not
489  * throw.
490  * @return true if the read-write lock is owned by this object,
491  * otherwise false.
492  *
493  * Since 1.2.1
494  */
495  bool is_owner() const {return owner;}
496 
497 /**
498  * This constructor locks for reading the read-write lock passed to
499  * it. It is not a cancellation point.
500  * @param rw_lock_ The read-write lock to be locked for reading.
501  * @exception Cgu::Thread::RWLockError Throws this exception if
502  * initialization of the read-write lock fails because the maximum
503  * number of read locks for the particular read-write lock in question
504  * has been reached. Usually this number is at or around INT_MAX so
505  * it is not usually useful to check for the exception except during
506  * debugging. This exception may also be thrown if the thread
507  * constructing this object already holds a write lock on the
508  * read-write lock in question. It will do this if the default pthread
509  * implementation returns EDEADLK in such a case instead of
510  * deadlocking. However as most default implementations will simply
511  * deadlock in such circumstances, it is usually not worth checking
512  * for this either except during debugging.
513  *
514  * Since 1.2.1
515  */
516  ReaderTrackLock(RWLock& rw_lock_): rw_lock(rw_lock_), owner(true) {if (rw_lock.reader_lock()) throw RWLockError();}
517 
518 /**
519  * This constructor takes a read-write lock already locked for reading
520  * (say as a result of RWLock::reader_trylock()), and takes management
521  * of that read lock operation. It is not a cancellation point. It
522  * does not throw.
523  * @param rw_lock_ The read-write lock to be managed for reading by
524  * this object.
525  * @param tag Pass the Cgu::Thread::locked enum tag to this parameter.
526  *
527  * Since 1.2.1
528  */
529  ReaderTrackLock(RWLock& rw_lock_, Locked tag): rw_lock(rw_lock_), owner(true) {}
530 
531 /**
532  * This constructor defers locking of the read-write lock for reading
533  * until an explicit call to lock() or trylock() is made. It is not a
534  * cancellation point. It does not throw.
535  * @param rw_lock_ The read-write lock to be managed for reading by
536  * this object.
537  * @param tag Pass the Cgu::Thread::defer enum tag to this parameter.
538  *
539  * Since 1.2.1
540  */
541  ReaderTrackLock(RWLock& rw_lock_, DeferLock tag): rw_lock(rw_lock_), owner(false) {}
542 
543 /**
544  * The destructor unlocks the read-write lock which is managed for
545  * reading if it is owned by this RWLock::ReaderTrackLock object
546  * (whether solely or with other read locks). It is not a
547  * cancellation point. It does not throw.
548  *
549  * Since 1.2.1
550  */
551  ~ReaderTrackLock() {if (owner) rw_lock.unlock();}
552 
553 /* Only has effect if --with-glib-memory-slices-compat or
554  * --with-glib-memory-slices-no-compat option picked */
556 };
557 
558 /**
559  * @class RWLock::WriterLock rw_lock.h c++-gtk-utils/rw_lock.h
560  * @brief A scoped locking class for exception safe RWLock write locking.
561  * @sa Thread::RWLock Thread::RWLock::WriterTrackLock Thread::RWLock::ReaderLock Thread::RWLock::ReaderTrackLock Thread::Thread
562  */
563 
565  RWLock& rw_lock;
566 
567  // locks cannot be copied
569  RWLock::WriterLock& operator=(const RWLock::WriterLock&);
570 public:
571 
572 /**
573  * Calls RWLock::writer_lock(), and so locks the read-write lock for
574  * writing and reacquires ownership. It blocks if the read-write lock
575  * is already locked for reading or writing until it becomes free.
576  * This method should normally only be called if a previous call has
577  * been made to RWLock::WriterLock::unlock() (that is, where the
578  * thread owning the RWLock::WriterLock object has temporarily allowed
579  * another thread to take the read-write lock concerned for reading or
580  * writing). It is not a cancellation point. It does not throw.
581  * @return 0 if successful, otherwise the pthread read-write lock
582  * error number.
583  * @note With this library implementation, the only pthread error
584  * number which could be returned by this method is EDEADLK, which it
585  * would do if the default pthread reader lock behaviour happens to
586  * return that error rather than deadlock where the thread calling
587  * this method already holds a read lock or write lock on the
588  * particular read-write lock in question. Most default
589  * implementations do not do this (they just deadlock) and hence the
590  * return value is usually not worth checking for except during
591  * debugging.
592  * @sa RWLock::WriterTrackLock
593  *
594  * Since 1.2.1
595  */
596  int lock() {return rw_lock.writer_lock();}
597 
598 /**
599  * Calls RWLock::writer_trylock(), and so tries to lock the read-write
600  * lock for writing and reacquire ownership, but returns immediately
601  * with value EBUSY if it is already locked for reading or writing.
602  * This method should normally only be called if a previous call has
603  * been made to RWLock::WriterLock::unlock() (that is, where the
604  * thread owning the RWLock::WriterLock object has temporarily allowed
605  * another thread to take the read-write lock concerned for reading or
606  * writing). It is not a cancellation point. It does not throw.
607  * @return 0 if successful, otherwise EBUSY.
608  * @note With this library implementation, the only pthread error
609  * number which could be returned by this method is EBUSY.
610  * @sa RWLock::WriterTrackLock
611  *
612  * Since 1.2.1
613  */
614  int trylock() {return rw_lock.writer_trylock();}
615 
616 /**
617  * Calls RWLock::unlock(), and so unlocks a locked read-write lock
618  * owned by the calling thread for writing and relinquishes ownership
619  * (so temporarily allowing another thread to take the read-write
620  * lock). This method should normally only be called if it is to be
621  * followed by a call to RWLock::WriterLock::lock() or a successful
622  * call to RWLock::WriterLock::trylock() before the RWLock::WriterLock
623  * object concerned goes out of scope (otherwise RWLock::WriterLock's
624  * destructor will attempt to unlock an already unlocked read-write
625  * lock or a read-write lock of which another thread has by then taken
626  * ownership - RWLock::WriterLock objects do not maintain state). See
627  * RWLock::WriterTrackLock::unlock() for a safe version of this
628  * method. It is not a cancellation point. It does not throw.
629  * @return 0 if successful, otherwise the pthread read-write lock
630  * error number.
631  * @note With this library implementation, the only pthread error
632  * number which could be returned by this method is EPERM because the
633  * calling thread does hold a lock on the particular read-write lock
634  * in question (however POSIX does not require that return value in
635  * that case and hence the return value is usually not worth checking
636  * for except during debugging).
637  * @sa RWLock::WriterTrackLock
638  *
639  * Since 1.2.1
640  */
641  int unlock() {return rw_lock.unlock();}
642 
643 /**
644  * This constructor locks for writing the read-write lock passed to
645  * it. It is not a cancellation point. It does not throw.
646  * @param rw_lock_ The read-write lock to be locked for writing.
647  *
648  * Since 1.2.1
649  */
650  WriterLock(RWLock& rw_lock_): rw_lock(rw_lock_) {rw_lock.writer_lock();}
651 
652 /**
653  * This constructor takes a read-write lock already locked for writing
654  * (say as a result of RWLock::writer_trylock()), and takes ownership
655  * of it. It is not a cancellation point. It does not throw.
656  * @param rw_lock_ The read-write lock to be managed for writing by
657  * this object.
658  * @param tag Pass the Cgu::Thread::locked enum tag to this parameter.
659  *
660  * Since 1.2.1
661  */
662  WriterLock(RWLock& rw_lock_, Locked tag): rw_lock(rw_lock_) {}
663 
664 /**
665  * The destructor unlocks the owned read-write lock. It is not a
666  * cancellation point. It does not throw.
667  *
668  * Since 1.2.1
669  */
670  ~WriterLock() {rw_lock.unlock();}
671 
672 /* Only has effect if --with-glib-memory-slices-compat or
673  * --with-glib-memory-slices-no-compat option picked */
675 };
676 
677 /**
678  * @class RWLock::WriterTrackLock rw_lock.h c++-gtk-utils/rw_lock.h
679  * @brief A scoped locking class for exception safe RWLock write
680  * locking which tracks the status of its read-write lock..
681  * @sa Thread::RWLock Thread::RWLock::WriterLock Thread::RWLock::ReaderLock Thread::RWLock::ReaderTrackLock Thread::Thread
682  *
683  * This class is similar to a RWLock::WriterLock object, except that
684  * it tracks whether the read-write lock it manages is locked for
685  * writing by the thread creating the RWLock::WriterTrackLock object
686  * (provided that, while the RWLock::WriterTrackLock object exists,
687  * the thread creating it only accesses the managed read-write lock
688  * for write-locking through that object). This enables
689  * RWLock::WriterTrackLock::unlock() to be used without it being
690  * followed later by a call to RWLock::WriterTrackLock::lock() or a
691  * successful call to RWLock::WriterTrackLock::trylock(), and also
692  * permits locking to be deferred until after construction of the
693  * RWLock::WriterTrackLock object. Note that only one thread may call
694  * the methods of any one RWLock::WriterTrackLock object, including
695  * causing its destructor to be invoked.
696  */
697 
699  RWLock& rw_lock;
700  bool owner;
701 
702  // locks cannot be copied
705 public:
706 
707 /**
708  * Calls RWLock::writer_lock(), and so locks the read-write lock for
709  * writing and acquires ownership. It blocks if the read-write lock
710  * is already locked for reading or writing until it becomes free.
711  * This method should normally only be called if a previous call has
712  * been made to RWLock::WriterTrackLock::unlock() or this
713  * RWLock::WriterTrackLock object has been constructed with the
714  * Thread::defer enum tag. It is not a cancellation point. It does
715  * not throw.
716  * @return 0 if successful, otherwise the pthread read-write lock
717  * error number.
718  * @note With this library implementation, the only pthread error
719  * number which could be returned by this method is EDEADLK, which it
720  * would do if the default pthread reader lock behaviour happens to
721  * return that error rather than deadlock where the thread calling
722  * this method already holds a read lock or write lock on the
723  * particular read-write lock in question. Most default
724  * implementations do not do this (they just deadlock) and hence the
725  * return value is usually not worth checking for except during
726  * debugging.
727  *
728  * Since 1.2.1
729  */
730  int lock() {int ret = rw_lock.writer_lock(); if (!owner) owner = !ret; return ret;}
731 
732 /**
733  * Calls RWLock::writer_trylock(), and so tries to lock the read-write
734  * lock for writing and acquire ownership, but returns immediately
735  * with value EBUSY if it is already locked for reading or writing.
736  * This method should normally only be called if a previous call has
737  * been made to RWLock::WriterTrackLock::unlock() or this
738  * RWLock::WriterTrackLock object has been constructed with the
739  * Thread::defer enum tag. It is not a cancellation point. It does
740  * not throw.
741  * @return 0 if successful, otherwise EBUSY.
742  * @note With this library implementation, the only pthread error
743  * number which could be returned by this method is EBUSY.
744  *
745  * Since 1.2.1
746  */
747  int trylock() {int ret = rw_lock.writer_trylock(); if (!owner) owner = !ret; return ret;}
748 
749 /**
750  * Calls RWLock::unlock(), and so unlocks a locked read-write lock
751  * owned by the calling thread for writing and relinquishes ownership.
752  * It will cause is_owner() to return false unless a subsequent call
753  * is made to lock() or a subsequent successful call is made to
754  * trylock(). It is not a cancellation point. It does not throw.
755  * @return 0 if successful, otherwise the pthread read-write lock
756  * error number.
757  * @note With this library implementation, the only pthread error
758  * number which could be returned by this method is EPERM because the
759  * calling thread does hold a lock on the particular read-write lock
760  * in question (however POSIX does not require that return value in
761  * that case and hence the return value is usually not worth checking
762  * for except during debugging).
763  *
764  * Since 1.2.1
765  */
766  int unlock() {int ret = rw_lock.unlock(); if (owner) owner = ret; return ret;}
767 
768 /**
769  * Indicates whether the read-write lock managed by this
770  * RWLock::ReaderTrackLock object is locked for writing by it and so
771  * owned by it. It does not throw.
772  * @return true if the read-write lock is owned by this object,
773  * otherwise false.
774  *
775  * Since 1.2.1
776  */
777  bool is_owner() const {return owner;}
778 
779 /**
780  * This constructor locks for writing the read-write lock passed to
781  * it. It is not a cancellation point. It does not throw.
782  * @param rw_lock_ The read-write lock to be locked for writing.
783  *
784  * Since 1.2.1
785  */
786  WriterTrackLock(RWLock& rw_lock_): rw_lock(rw_lock_), owner(true) {rw_lock.writer_lock();}
787 
788 /**
789  * This constructor takes a read-write lock already locked for writing
790  * (say as a result of RWLock::writer_trylock()), and takes ownership
791  * of it. It is not a cancellation point. It does not throw.
792  * @param rw_lock_ The read-write lock to be managed for writing by
793  * this object.
794  * @param tag Pass the Cgu::Thread::locked enum tag to this parameter.
795  *
796  * Since 1.2.1
797  */
798  WriterTrackLock(RWLock& rw_lock_, Locked tag): rw_lock(rw_lock_), owner(true) {}
799 
800 /**
801  * This constructor defers locking of the read-write lock for writing
802  * until an explicit call to lock() or trylock() is made. It is not a
803  * cancellation point. It does not throw.
804  * @param rw_lock_ The read-write lock to be managed for writing by
805  * this object.
806  * @param tag Pass the Cgu::Thread::defer enum tag to this parameter.
807  *
808  * Since 1.2.1
809  */
810  WriterTrackLock(RWLock& rw_lock_, DeferLock tag): rw_lock(rw_lock_), owner(false) {}
811 
812 /**
813  * The destructor unlocks the read-write lock which is managed for
814  * writing if it is owned by this RWLock::WriterTrackLock object. It
815  * is not a cancellation point. It does not throw.
816  *
817  * Since 1.2.1
818  */
819  ~WriterTrackLock() {if (owner) rw_lock.unlock();}
820 
821 /* Only has effect if --with-glib-memory-slices-compat or
822  * --with-glib-memory-slices-no-compat option picked */
824 };
825 
826 } // namespace Thread
827 
828 } // namespace Cgu
829 
830 #endif
Cgu::Thread::RWLock::ReaderLock::trylock
int trylock()
Definition: rw_lock.h:305
Cgu
Definition: application.h:45
Cgu::Thread::RWLock::WriterTrackLock::lock
int lock()
Definition: rw_lock.h:730
Cgu::Thread::RWLock::ReaderTrackLock::~ReaderTrackLock
~ReaderTrackLock()
Definition: rw_lock.h:551
Cgu::Thread::RWLock::WriterTrackLock::WriterTrackLock
WriterTrackLock(RWLock &rw_lock_, DeferLock tag)
Definition: rw_lock.h:810
Cgu::Thread::RWLock::WriterLock::unlock
int unlock()
Definition: rw_lock.h:641
Cgu::Thread::RWLock::ReaderTrackLock::ReaderTrackLock
ReaderTrackLock(RWLock &rw_lock_, DeferLock tag)
Definition: rw_lock.h:541
Cgu::Thread::RWLock::WriterTrackLock::is_owner
bool is_owner() const
Definition: rw_lock.h:777
Cgu::Thread::RWLock::WriterTrackLock
A scoped locking class for exception safe RWLock write locking which tracks the status of its read-wr...
Definition: rw_lock.h:698
Cgu::Thread::RWLock::RWLock
RWLock()
Definition: rw_lock.h:222
Cgu::Thread::RWLock::ReaderTrackLock::lock
int lock()
Definition: rw_lock.h:441
Cgu::Thread::RWLock::writer_trylock
int writer_trylock()
Definition: rw_lock.h:186
Cgu::Thread::RWLock::ReaderTrackLock::ReaderTrackLock
ReaderTrackLock(RWLock &rw_lock_)
Definition: rw_lock.h:516
Cgu::Thread::RWLock::ReaderTrackLock::is_owner
bool is_owner() const
Definition: rw_lock.h:495
Cgu::Thread::RWLock::ReaderTrackLock
A scoped locking class for exception safe RWLock read locking which tracks the status of its read-wri...
Definition: rw_lock.h:406
Cgu::Thread::RWLock::reader_lock
int reader_lock()
Definition: rw_lock.h:132
Cgu::Thread::RWLock::reader_trylock
int reader_trylock()
Definition: rw_lock.h:153
Cgu::Thread::RWLock::WriterLock::~WriterLock
~WriterLock()
Definition: rw_lock.h:670
Cgu::Thread::RWLock::ReaderLock::ReaderLock
ReaderLock(RWLock &rw_lock_)
Definition: rw_lock.h:355
Cgu::Thread::RWLock::WriterLock::trylock
int trylock()
Definition: rw_lock.h:614
Cgu::Thread::RWLock::WriterLock::lock
int lock()
Definition: rw_lock.h:596
Cgu::Thread::RWLock::ReaderLock::lock
int lock()
Definition: rw_lock.h:280
Cgu::Thread::RWLock::WriterTrackLock::unlock
int unlock()
Definition: rw_lock.h:766
Cgu::Thread::RWLock::WriterTrackLock::WriterTrackLock
WriterTrackLock(RWLock &rw_lock_, Locked tag)
Definition: rw_lock.h:798
Cgu::Thread::RWLockError
Definition: rw_lock.h:59
Cgu::Thread::RWLock::WriterTrackLock::trylock
int trylock()
Definition: rw_lock.h:747
Cgu::Thread::RWLock::~RWLock
~RWLock()
Definition: rw_lock.h:230
Cgu::Thread::RWLock::ReaderLock::ReaderLock
ReaderLock(RWLock &rw_lock_, Locked tag)
Definition: rw_lock.h:368
Cgu::Thread::RWLock::WriterLock::WriterLock
WriterLock(RWLock &rw_lock_, Locked tag)
Definition: rw_lock.h:662
Cgu::Thread::RWLock::WriterLock::WriterLock
WriterLock(RWLock &rw_lock_)
Definition: rw_lock.h:650
Cgu::Thread::DeferLock
DeferLock
Definition: mutex.h:184
Cgu::Thread::RWLock::writer_lock
int writer_lock()
Definition: rw_lock.h:173
Cgu::Thread::RWLockError::what
virtual const char * what() const
Definition: rw_lock.h:60
CGU_GLIB_MEMORY_SLICES_FUNCS
#define CGU_GLIB_MEMORY_SLICES_FUNCS
Definition: cgu_config.h:84
Cgu::Thread::RWLock::ReaderLock::~ReaderLock
~ReaderLock()
Definition: rw_lock.h:376
Cgu::Thread::Locked
Locked
Definition: mutex.h:181
Cgu::Thread::RWLock::ReaderTrackLock::ReaderTrackLock
ReaderTrackLock(RWLock &rw_lock_, Locked tag)
Definition: rw_lock.h:529
Cgu::Thread::RWLock::ReaderTrackLock::unlock
int unlock()
Definition: rw_lock.h:483
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::Thread::RWLock
A wrapper class for pthread read-write locks.
Definition: rw_lock.h:96
Cgu::Thread::RWLock::ReaderLock
A scoped locking class for exception safe RWLock read locking.
Definition: rw_lock.h:243
Cgu::Thread::RWLock::ReaderLock::unlock
int unlock()
Definition: rw_lock.h:334
Cgu::Thread::RWLock::ReaderTrackLock::trylock
int trylock()
Definition: rw_lock.h:463
Cgu::Thread::RWLock::WriterLock
A scoped locking class for exception safe RWLock write locking.
Definition: rw_lock.h:564
Cgu::Thread::RWLock::unlock
int unlock()
Definition: rw_lock.h:209
cgu_config.h
Cgu::Thread::RWLock::WriterTrackLock::WriterTrackLock
WriterTrackLock(RWLock &rw_lock_)
Definition: rw_lock.h:786
Cgu::Thread::RWLock::WriterTrackLock::~WriterTrackLock
~WriterTrackLock()
Definition: rw_lock.h:819