-
-
Notifications
You must be signed in to change notification settings - Fork 442
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
libs/core/synchronization/include/hpx/synchronization/detail/range_lock_impl.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
110
libs/core/synchronization/include/hpx/synchronization/range_lock.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |