summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/threads/read_write_mutex_extension.h
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/threads/read_write_mutex_extension.h')
-rw-r--r--ml/dlib/dlib/threads/read_write_mutex_extension.h177
1 files changed, 177 insertions, 0 deletions
diff --git a/ml/dlib/dlib/threads/read_write_mutex_extension.h b/ml/dlib/dlib/threads/read_write_mutex_extension.h
new file mode 100644
index 000000000..20e5d5ed8
--- /dev/null
+++ b/ml/dlib/dlib/threads/read_write_mutex_extension.h
@@ -0,0 +1,177 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_READ_WRITE_MUTEX_EXTENSIOn_
+#define DLIB_READ_WRITE_MUTEX_EXTENSIOn_
+
+#include "threads_kernel.h"
+#include "read_write_mutex_extension_abstract.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ class read_write_mutex
+ {
+ /*!
+ INITIAL VALUE
+ - max_locks == defined by constructor
+ - available_locks == max_locks
+ - write_lock_in_progress == false
+ - write_lock_active == false
+
+ CONVENTION
+ - Each time someone gets a read only lock they take one of the "available locks"
+ and each write lock takes all possible locks (i.e. max_locks). The number of
+ available locks is recorded in available_locks. Any time you try to lock this
+ object and there aren't available locks you have to wait.
+
+ - max_locks == max_readonly_locks()
+
+ - if (some thread is on the process of obtaining a write lock) then
+ - write_lock_in_progress == true
+ - else
+ - write_lock_in_progress == false
+
+ - if (some thread currently has a write lock on this mutex) then
+ - write_lock_active == true
+ - else
+ - write_lock_active == false
+ !*/
+
+ public:
+
+ read_write_mutex (
+ ) : s(m),
+ max_locks(0xFFFFFFFF),
+ available_locks(max_locks),
+ write_lock_in_progress(false),
+ write_lock_active(false)
+ {}
+
+ explicit read_write_mutex (
+ unsigned long max_locks_
+ ) : s(m),
+ max_locks(max_locks_),
+ available_locks(max_locks_),
+ write_lock_in_progress(false),
+ write_lock_active(false)
+ {
+ // make sure requires clause is not broken
+ DLIB_ASSERT(max_locks > 0,
+ "\t read_write_mutex::read_write_mutex(max_locks)"
+ << "\n\t You must give a non-zero value for max_locks"
+ << "\n\t this: " << this
+ );
+ }
+
+ ~read_write_mutex (
+ )
+ {}
+
+ void lock (
+ ) const
+ {
+ m.lock();
+
+ // If another write lock is already in progress then wait for it to finish
+ // before we start trying to grab all the available locks. This way we
+ // don't end up fighting over the locks.
+ while (write_lock_in_progress)
+ s.wait();
+
+ // grab the right to perform a write lock
+ write_lock_in_progress = true;
+
+ // now start grabbing all the locks
+ unsigned long locks_obtained = available_locks;
+ available_locks = 0;
+ while (locks_obtained != max_locks)
+ {
+ s.wait();
+ locks_obtained += available_locks;
+ available_locks = 0;
+ }
+
+ write_lock_in_progress = false;
+ write_lock_active = true;
+
+ m.unlock();
+ }
+
+ void unlock (
+ ) const
+ {
+ m.lock();
+
+ // only do something if there really was a lock in place
+ if (write_lock_active)
+ {
+ available_locks = max_locks;
+ write_lock_active = false;
+ s.broadcast();
+ }
+
+ m.unlock();
+ }
+
+ void lock_readonly (
+ ) const
+ {
+ m.lock();
+
+ while (available_locks == 0)
+ s.wait();
+
+ --available_locks;
+
+ m.unlock();
+ }
+
+ void unlock_readonly (
+ ) const
+ {
+ m.lock();
+
+ // If this condition is false then it means there are no more readonly locks
+ // to free. So we don't do anything.
+ if (available_locks != max_locks && !write_lock_active)
+ {
+ ++available_locks;
+
+ // only perform broadcast when there is another thread that might be listening
+ if (available_locks == 1 || write_lock_in_progress)
+ {
+ s.broadcast();
+ }
+ }
+
+ m.unlock();
+ }
+
+ unsigned long max_readonly_locks (
+ ) const
+ {
+ return max_locks;
+ }
+
+ private:
+ mutex m;
+ signaler s;
+ const unsigned long max_locks;
+ mutable unsigned long available_locks;
+ mutable bool write_lock_in_progress;
+ mutable bool write_lock_active;
+
+ // restricted functions
+ read_write_mutex(read_write_mutex&); // copy constructor
+ read_write_mutex& operator=(read_write_mutex&); // assignment operator
+ };
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_READ_WRITE_MUTEX_EXTENSIOn_
+
+