You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
5.0 KiB
C++
178 lines
5.0 KiB
C++
// 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_
|
|
|
|
|