Skip to content

Commit

Permalink
Merge c33c9a1 into 89f342b
Browse files Browse the repository at this point in the history
  • Loading branch information
Johan511 authored Nov 2, 2023
2 parents 89f342b + c33c9a1 commit 9da61de
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 0 deletions.
2 changes: 2 additions & 0 deletions libs/core/synchronization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ set(synchronization_headers
hpx/synchronization/counting_semaphore.hpp
hpx/synchronization/detail/condition_variable.hpp
hpx/synchronization/detail/counting_semaphore.hpp
hpx/synchronization/detail/range_lock_impl.hpp
hpx/synchronization/detail/sliding_semaphore.hpp
hpx/synchronization/event.hpp
hpx/synchronization/latch.hpp
hpx/synchronization/lock_types.hpp
hpx/synchronization/mutex.hpp
hpx/synchronization/no_mutex.hpp
hpx/synchronization/once.hpp
hpx/synchronization/range_lock.hpp
hpx/synchronization/recursive_mutex.hpp
hpx/synchronization/shared_mutex.hpp
hpx/synchronization/sliding_semaphore.hpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#pragma once

#include <hpx/execution_base/this_thread.hpp>

#include <atomic>
#include <boost/container/flat_map.hpp>
#include <cstddef>
#include <utility>
#include <vector>

namespace hpx::synchronization::detail {

template <typename Lock, template <typename> typename Guard>
class RangeLock
{
template <typename Key, typename Value>
using MapTy = boost::container::flat_map<Key, Value>;

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;

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);
};

template <class Lock, template <class> class Guard>
std::size_t RangeLock<Lock, Guard>::lock(std::size_t begin, std::size_t end)
{
std::size_t lockId = 0;
bool localFlag = false;
std::size_t blockIdx;

std::shared_ptr<std::atomic_bool> waitingFlag;

while (lockId == 0)
{
{
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));
lockId = counter; // to get rid of codacy warning
return counter;
}
localFlag = false;
}
auto pred = [&waitingFlag]() noexcept {
return waitingFlag->load();
};
util::yield_while<true>(pred, "hpx::range_lock::lock");
}
return lockId; // should not reach here
}

template <class Lock, template <class> class Guard>
void RangeLock<Lock, Guard>::unlock(std::size_t lockId)
{
const Guard lock_guard(mtx);

rangeMap.erase(lockId);

waiting[lockId]->store(true);

waiting.erase(lockId);
return;
}

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)
{
std::size_t b = it.second.first;
std::size_t e = it.second.second;

if (!(e < begin) && !(end < b))
{
return 0;
}
}
rangeMap[++counter] = {begin, end};
return counter;
}
} // namespace hpx::synchronization::detail
110 changes: 110 additions & 0 deletions libs/core/synchronization/include/hpx/synchronization/range_lock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#pragma once

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

#include <functional>
#include <mutex>

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

// Lock guards for range_lock
namespace hpx::synchronization {

template <typename RangeLock>
class range_guard
{
std::reference_wrapper<RangeLock> lockRef;
std::size_t lockId = 0;

public:
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);
}
};

} // namespace hpx::synchronization

namespace hpx::synchronization {

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

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

~range_unique_lock()
{
lockRef.get().unlock(lockId);
}

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);
}

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

void unlock()
{
lockRef.get().unlock(lockId);
lockId = 0;
}

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

RangeLock* release()
{
RangeLock* mtx = lockRef.get();
lockRef = nullptr;
lockId = 0;
return mtx;
}

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

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

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

} // namespace hpx::synchronization
1 change: 1 addition & 0 deletions libs/core/synchronization/tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ set(tests
local_barrier_reset
local_event
local_mutex
range_lock
sliding_semaphore
stop_token
stop_token_cb2
Expand Down
28 changes: 28 additions & 0 deletions libs/core/synchronization/tests/unit/range_lock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <hpx/hpx_main.hpp>
#include <hpx/synchronization/mutex.hpp>
#include <hpx/synchronization/range_lock.hpp>

int main()
{
{
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 9da61de

Please sign in to comment.