Skip to content

Commit

Permalink
added std::lock_guard and std::unique_lock_guard for range_lock
Browse files Browse the repository at this point in the history
  • Loading branch information
Johan511 committed Nov 2, 2023
1 parent 94ad707 commit a97f92f
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 82 deletions.
163 changes: 84 additions & 79 deletions libs/core/synchronization/include/hpx/synchronization/range_lock.hpp
Original file line number Diff line number Diff line change
@@ -1,104 +1,109 @@
#pragma once

#include <atomic>
#include <boost/container/flat_map.hpp>
#include <map>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <vector>

#include <hpx/synchronization/detail/range_lock_impl.hpp>
#include <hpx/synchronization/spinlock.hpp>

namespace hpx::synchronization {
using range_lock =
hpx::synchronization::detail::RangeLock<hpx::spinlock, std::lock_guard>;
}

template <typename Lock, template <typename> typename Guard>
class RangeLock
{
template <typename Key, typename Value>
using MapTy = boost::container::flat_map<Key, Value>;
// Lock guards for range_lock
namespace hpx::synchronization {

Lock mtx;
std::size_t counter = 0;
MapTy<std::size_t, std::pair<std::size_t, std::size_t>> rangeMap;
MapTy<std::size_t, std::shared_ptr<std::atomic_bool>> waiting;
template <typename RangeLock>
class range_guard
{
std::reference_wrapper<RangeLock> lockRef;
std::size_t lockId = 0;

public:
std::size_t lock(std::size_t begin, std::size_t end);
std::size_t try_lock(std::size_t begin, std::size_t end);
void unlock(std::size_t lockId);
range_guard(RangeLock& lock, std::size_t begin, std::size_t end)
: lockRef(lock)
{
lockId = lockRef.get().lock(begin, end);
}
~range_guard()
{
lockRef.get().unlock(lockId);
}
};

template <class Lock, template <class> class Guard>
std::size_t RangeLock<Lock, Guard>::lock(std::size_t begin, std::size_t end)
} // namespace hpx::synchronization

namespace hpx::synchronization {

template <typename RangeLock>
class range_unique_lock
{
std::reference_wrapper<RangeLock> lockRef;
std::size_t lockId = 0;
bool localFlag = false;
std::size_t blockIdx;

std::shared_ptr<std::atomic_bool> waitingFlag;
public:
range_unique_lock(RangeLock& lock, std::size_t begin, std::size_t end)
: lockRef(lock)
{
lockId = lockRef.get().lock(begin, end);
}

while (lockId == 0)
~range_unique_lock()
{
{
const Guard<Lock> lock_guard(mtx);
for (auto const& it : rangeMap)
{
std::size_t b = it.second.first;
std::size_t e = it.second.second;

if (!(e < begin) & !(end < b))
{
blockIdx = it.first;
localFlag = true;
waitingFlag = waiting[blockIdx];
break;
}
}
if (localFlag == false)
{
++counter;
rangeMap[counter] = {begin, end};
waiting[counter] = std::shared_ptr<std::atomic_bool>(
new std::atomic_bool(false));
return counter;
}
localFlag = false;
}
while (waitingFlag->load() == false)
{
}
lockRef.get().unlock(lockId);
}
return lockId;
}

template <class Lock, template <class> class Guard>
void RangeLock<Lock, Guard>::unlock(std::size_t lockId)
{
const Guard lock_guard(mtx);
void operator=(range_unique_lock<RangeLock>&& lock)
{
lockRef.get().unlock(lockId);
lockRef = lock.lockRef;
lockId = lock.lockRef.get().lock();
}

void lock(std::size_t begin, std::size_t end)
{
lockId = lockRef.get().lock(begin, end);
}

rangeMap.erase(lockId);
void try_lock(std::size_t begin, std::size_t end)
{
lockId = lockRef.get().try_lock(begin, end);
}

waiting[lockId]->store(true);
void unlock()
{
lockRef.get().unlock(lockId);
lockId = 0;
}

waiting.erase(lockId);
return;
}
void swap(std::unique_lock<RangeLock>& uLock)
{
std::swap(lockRef, uLock.lockRef);
std::swap(lockId, uLock.lockId);
}

template <class Lock, template <class> class Guard>
std::size_t RangeLock<Lock, Guard>::try_lock(
std::size_t begin, std::size_t end)
{
const Guard lock_guard(mtx);
for (auto const& it : rangeMap)
RangeLock* release()
{
std::size_t b = it.second.first;
std::size_t e = it.second.second;
RangeLock* mtx = lockRef.get();
lockRef = nullptr;
lockId = 0;
return mtx;
}

if (!(e < begin) && !(end < b))
{
return 0;
}
operator bool() const
{
return lockId != 0;
}
rangeMap[++counter] = {begin, end};
return counter;
}
} // namespace hpx::synchronization

bool owns_lock() const
{
return lockId != 0;
}

RangeLock* mutex() const
{
return lockRef.get();
}
};

} // namespace hpx::synchronization
24 changes: 21 additions & 3 deletions libs/core/synchronization/tests/unit/range_lock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,25 @@

int main()
{
hpx::synchronization::RangeLock<hpx::mutex, std::lock_guard> rl;
std::size_t x = rl.lock(0, 10);
rl.unlock(x);
{
hpx::synchronization::range_lock rl;
std::size_t x = rl.lock(0, 10);
rl.unlock(x);
return 0;
}

{
hpx::synchronization::range_lock rl;

hpx::synchronization::range_guard<hpx::synchronization::range_lock> rg(
rl, 0, 10);
}

{
hpx::synchronization::range_lock rl;

hpx::synchronization::range_unique_lock<
hpx::synchronization::range_lock>
rg(rl, 0, 10);
}
}

0 comments on commit a97f92f

Please sign in to comment.