Mirror von
https://github.com/tkuschel/bees.git
synchronisiert 2026-06-19 06:57:54 +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>
Dieser Commit ist enthalten in:
@@ -13,6 +13,7 @@ CRUCIBLE_OBJS = \
|
||||
extentwalker.o \
|
||||
fd.o \
|
||||
fs.o \
|
||||
multilock.o \
|
||||
ntoa.o \
|
||||
path.o \
|
||||
process.o \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren