mirror of
https://github.com/Zygo/bees.git
synced 2025-08-02 13:53:28 +02:00
multilocker: serialize conflicting parallel operations
For performance or workaround reasons we sometimes have to avoid doing two conflicting operations at the same time, but we can still run any number of non-conflicting operations in parallel. MultiLocker (suggestions for a better class name welcome) blocks the calling thread until there are no threads attempting to run a conflicting operation. Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
@@ -13,6 +13,7 @@ CRUCIBLE_OBJS = \
|
||||
extentwalker.o \
|
||||
fd.o \
|
||||
fs.o \
|
||||
multilock.o \
|
||||
ntoa.o \
|
||||
path.o \
|
||||
process.o \
|
||||
|
72
lib/multilock.cc
Normal file
72
lib/multilock.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "crucible/multilock.h"
|
||||
|
||||
#include "crucible/error.h"
|
||||
|
||||
namespace crucible {
|
||||
using namespace std;
|
||||
|
||||
MultiLocker::LockHandle::LockHandle(const string &type, MultiLocker &parent) :
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MultiLocker::LockHandle::set_locked(const bool state)
|
||||
{
|
||||
m_locked = state;
|
||||
}
|
||||
|
||||
MultiLocker::LockHandle::~LockHandle()
|
||||
{
|
||||
if (m_locked) {
|
||||
m_parent.put_lock(m_type);
|
||||
m_locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MultiLocker::is_lock_available(const string &type)
|
||||
{
|
||||
for (const auto &i : m_counters) {
|
||||
if (i.second != 0 && i.first != type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MultiLocker::put_lock(const string &type)
|
||||
{
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
auto &counter = m_counters[type];
|
||||
THROW_CHECK2(runtime_error, type, counter, counter > 0);
|
||||
--counter;
|
||||
if (counter == 0) {
|
||||
m_cv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<MultiLocker::LockHandle>
|
||||
MultiLocker::get_lock_private(const string &type)
|
||||
{
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
m_counters.insert(make_pair(type, size_t(0)));
|
||||
while (!is_lock_available(type)) {
|
||||
m_cv.wait(lock);
|
||||
}
|
||||
const auto rv = make_shared<LockHandle>(type, *this);
|
||||
++m_counters[type];
|
||||
rv->set_locked(true);
|
||||
return rv;
|
||||
}
|
||||
|
||||
shared_ptr<MultiLocker::LockHandle>
|
||||
MultiLocker::get_lock(const string &type)
|
||||
{
|
||||
static MultiLocker s_process_instance;
|
||||
return s_process_instance.get_lock_private(type);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user