-
-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added std::lock_guard and std::unique_lock_guard for range_lock
- Loading branch information
Showing
3 changed files
with
211 additions
and
82 deletions.
There are no files selected for viewing
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 |
163 changes: 84 additions & 79 deletions
163
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 |
---|---|---|
@@ -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 |
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