-
Notifications
You must be signed in to change notification settings - Fork 97
use shared mutex for acessing/creating symbols #617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: wip
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| #pragma once | ||
|
|
||
| #if defined(_WIN32) || defined(_WIN64) | ||
| #define GRINGO_PLATFORM_WINDOWS 1 | ||
| #else | ||
| #define GRINGO_PLATFORM_WINDOWS 0 | ||
| #endif | ||
|
rkaminsk marked this conversation as resolved.
|
||
|
|
||
| #if !GRINGO_PLATFORM_WINDOWS && (defined(__unix__) || defined(__APPLE__)) | ||
| #define GRINGO_PLATFORM_POSIX 1 | ||
| #else | ||
| #define GRINGO_PLATFORM_POSIX 0 | ||
| #endif | ||
|
|
||
| #include <cstdio> | ||
| #include <cstdlib> | ||
| #include <cstring> | ||
|
|
||
| #if GRINGO_PLATFORM_WINDOWS | ||
| #define WIN32_LEAN_AND_MEAN | ||
| #define NOMINMAX | ||
| #include <Windows.h> | ||
|
rkaminsk marked this conversation as resolved.
|
||
| #elif GRINGO_PLATFORM_POSIX | ||
| #include <pthread.h> | ||
| #else | ||
| #include <shared_mutex> | ||
| #endif | ||
|
|
||
| namespace Gringo { | ||
|
|
||
| #if GRINGO_PLATFORM_POSIX | ||
| namespace Detail { | ||
|
|
||
| inline void check_pthread_call(char const *fun, int code) noexcept { | ||
| if (code != 0) { | ||
| std::fprintf(stderr, "fatal: %s failed: %s\n", fun, std::strerror(code)); | ||
| std::abort(); | ||
| } | ||
| } | ||
|
|
||
| } // namespace Detail | ||
| #endif | ||
|
|
||
| class SharedMutex { | ||
|
BenKaufmann marked this conversation as resolved.
|
||
| public: | ||
| SharedMutex() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| InitializeSRWLock(&srw_); | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| Detail::check_pthread_call("pthread_rwlock_init", pthread_rwlock_init(&rw_, nullptr)); | ||
| #endif | ||
| } | ||
|
|
||
| ~SharedMutex() noexcept { | ||
| #if GRINGO_PLATFORM_POSIX | ||
| Detail::check_pthread_call("pthread_rwlock_destroy", pthread_rwlock_destroy(&rw_)); | ||
| #endif | ||
|
rkaminsk marked this conversation as resolved.
|
||
| } | ||
|
|
||
| SharedMutex(const SharedMutex &) = delete; | ||
| SharedMutex &operator=(const SharedMutex &) = delete; | ||
| SharedMutex(SharedMutex &&) = delete; | ||
| SharedMutex &operator=(SharedMutex &&) = delete; | ||
|
|
||
| void lock_shared() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| AcquireSRWLockShared(&srw_); | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| Detail::check_pthread_call("pthread_rwlock_rdlock", pthread_rwlock_rdlock(&rw_)); | ||
| #else | ||
| mtx_.lock_shared(); | ||
| #endif | ||
| } | ||
|
|
||
| bool try_lock_shared() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| return TryAcquireSRWLockShared(&srw_) != 0; | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| return pthread_rwlock_tryrdlock(&rw_) == 0; | ||
| #else | ||
| return mtx_.try_lock_shared(); | ||
| #endif | ||
| } | ||
|
|
||
| void unlock_shared() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| ReleaseSRWLockShared(&srw_); | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| Detail::check_pthread_call("pthread_rwlock_unlock", pthread_rwlock_unlock(&rw_)); | ||
| #else | ||
| mtx_.unlock_shared(); | ||
| #endif | ||
| } | ||
|
|
||
| void lock() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| AcquireSRWLockExclusive(&srw_); | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| Detail::check_pthread_call("pthread_rwlock_wrlock", pthread_rwlock_wrlock(&rw_)); | ||
| #else | ||
| mtx_.lock(); | ||
| #endif | ||
| } | ||
|
|
||
| bool try_lock() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| return TryAcquireSRWLockExclusive(&srw_) != 0; | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| return pthread_rwlock_trywrlock(&rw_) == 0; | ||
| #else | ||
| return mtx_.try_lock(); | ||
| #endif | ||
| } | ||
|
|
||
| void unlock() noexcept { | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| ReleaseSRWLockExclusive(&srw_); | ||
|
BenKaufmann marked this conversation as resolved.
|
||
| #elif GRINGO_PLATFORM_POSIX | ||
| Detail::check_pthread_call("pthread_rwlock_unlock", pthread_rwlock_unlock(&rw_)); | ||
| #else | ||
| mtx_.unlock(); | ||
| #endif | ||
| } | ||
|
|
||
| private: | ||
| #if GRINGO_PLATFORM_WINDOWS | ||
| SRWLOCK srw_; | ||
| #elif GRINGO_PLATFORM_POSIX | ||
| pthread_rwlock_t rw_; | ||
| #else | ||
| std::shared_timed_mutex mtx_; | ||
| #endif | ||
| }; | ||
|
|
||
| } // namespace Gringo | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,9 +25,11 @@ | |
| #include <algorithm> | ||
| #include <cstring> | ||
| #include <gringo/hash_set.hh> | ||
| #include <gringo/shared_mutex.hh> | ||
| #include <gringo/symbol.hh> | ||
| #include <iterator> | ||
| #include <mutex> | ||
| #include <shared_mutex> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that you are using this C++14-header, have you considered using
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the code path is performance critical, I'd rather stick with the the lightweight locking primitives. I should however use the shared_timed_mutex as the fallback instead of the std::mutex.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked at the implementation of std::shared_timed_mutex and at least on linux we could even just use it. The problem is that we support really old macos platforms (10.9) where it is not available. That's why I would simply keep the current implementation. It should be more or less the same as the stl implementation. |
||
|
|
||
| #ifdef _MSC_VER | ||
| #pragma warning(disable : 4200) // nonstandard extension used: zero-sized array in struct/union | ||
|
|
@@ -82,24 +84,28 @@ template <class T> struct UniqueConstruct { | |
| using Set = hash_set<T, typename T::Hash, typename T::EqualTo>; | ||
|
|
||
| template <class U> static T const &construct(U &&x) { | ||
| // TODO: in C++17 this can use a read/write lock to not block reading threads | ||
| size_t hash = typename T::Hash{}(x); | ||
| std::lock_guard<std::mutex> g(mutex_); | ||
| auto it = set_.find(x, hash); | ||
| if (it != set_.end()) { | ||
| return *it; | ||
| { | ||
| auto lock = std::shared_lock<SharedMutex>{mutex_}; | ||
| auto it = set_.find(x, hash); | ||
| if (it != set_.end()) { | ||
| return *it; | ||
| } | ||
| } | ||
| { | ||
| auto lock = std::unique_lock<SharedMutex>{mutex_}; | ||
| return *set_.insert(T{std::forward<U>(x), hash}).first; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
| return *set_.insert(T{std::forward<U>(x), hash}).first; | ||
| } | ||
|
|
||
| private: | ||
| static Set set_; // NOLINT | ||
| static std::mutex mutex_; // NOLINT | ||
| static Set set_; // NOLINT | ||
| static SharedMutex mutex_; // NOLINT | ||
| }; | ||
|
|
||
| template <class T> typename UniqueConstruct<T>::Set UniqueConstruct<T>::set_; // NOLINT | ||
|
|
||
| template <class T> typename std::mutex UniqueConstruct<T>::mutex_; // NOLINT | ||
| template <class T> Gringo::SharedMutex UniqueConstruct<T>::mutex_; // NOLINT | ||
|
|
||
| template <class T, class U> T const &construct_unique(U &&x) { | ||
| return UniqueConstruct<T>::construct(std::forward<U>(x)); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.