-
-
Notifications
You must be signed in to change notification settings - Fork 437
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
2 changed files
with
105 additions
and
82 deletions.
There are no files selected for viewing
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