1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 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_
|