Skip to content

Commit 9e2142d

Browse files
Replace spinlock with condition_variable (#1356)
Spinlock loads the CPU quite substantially, reducing it by using condition_variable Relates-To: OAM-1784 Signed-off-by: Andrey Kashcheev <[email protected]>
1 parent 256fdcf commit 9e2142d

File tree

2 files changed

+45
-9
lines changed

2 files changed

+45
-9
lines changed

olp-cpp-sdk-dataservice-read/src/repositories/NamedMutex.cpp

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ namespace repository {
3030

3131
class NamedMutexStorage::Impl {
3232
public:
33-
std::mutex& AquireLock(const std::string& resource);
33+
std::mutex& AcquireLock(const std::string& resource);
3434
void ReleaseLock(const std::string& resource);
35+
std::condition_variable& GetLockCondition(const std::string& resource);
36+
std::mutex& GetLockMutex(const std::string& resource);
3537
void SetError(const std::string& resource, const client::ApiError& error);
3638
boost::optional<client::ApiError> GetError(const std::string& resource);
3739

@@ -40,13 +42,15 @@ class NamedMutexStorage::Impl {
4042
std::mutex mutex;
4143
uint32_t use_count{0u};
4244
boost::optional<client::ApiError> optional_error;
45+
std::condition_variable lock_condition;
46+
std::mutex lock_mutex;
4347
};
4448

4549
std::mutex mutex_;
4650
std::unordered_map<std::string, RefCounterMutex> mutexes_;
4751
};
4852

49-
std::mutex& NamedMutexStorage::Impl::AquireLock(const std::string& resource) {
53+
std::mutex& NamedMutexStorage::Impl::AcquireLock(const std::string& resource) {
5054
std::lock_guard<std::mutex> lock(mutex_);
5155
RefCounterMutex& ref_mutex = mutexes_[resource];
5256
ref_mutex.use_count++;
@@ -66,6 +70,19 @@ void NamedMutexStorage::Impl::ReleaseLock(const std::string& resource) {
6670
}
6771
}
6872

73+
std::condition_variable& NamedMutexStorage::Impl::GetLockCondition(
74+
const std::string& resource) {
75+
std::lock_guard<std::mutex> lock(mutex_);
76+
RefCounterMutex& ref_mutex = mutexes_[resource];
77+
return ref_mutex.lock_condition;
78+
}
79+
80+
std::mutex& NamedMutexStorage::Impl::GetLockMutex(const std::string& resource) {
81+
std::lock_guard<std::mutex> lock(mutex_);
82+
RefCounterMutex& ref_mutex = mutexes_[resource];
83+
return ref_mutex.lock_mutex;
84+
}
85+
6986
void NamedMutexStorage::Impl::SetError(const std::string& resource,
7087
const client::ApiError& error) {
7188
std::lock_guard<std::mutex> lock(mutex_);
@@ -88,14 +105,23 @@ boost::optional<client::ApiError> NamedMutexStorage::Impl::GetError(
88105

89106
NamedMutexStorage::NamedMutexStorage() : impl_(std::make_shared<Impl>()) {}
90107

91-
std::mutex& NamedMutexStorage::AquireLock(const std::string& resource) {
92-
return impl_->AquireLock(resource);
108+
std::mutex& NamedMutexStorage::AcquireLock(const std::string& resource) {
109+
return impl_->AcquireLock(resource);
93110
}
94111

95112
void NamedMutexStorage::ReleaseLock(const std::string& resource) {
96113
impl_->ReleaseLock(resource);
97114
}
98115

116+
std::condition_variable& NamedMutexStorage::GetLockCondition(
117+
const std::string& resource) {
118+
return impl_->GetLockCondition(resource);
119+
}
120+
121+
std::mutex& NamedMutexStorage::GetLockMutex(const std::string& resource) {
122+
return impl_->GetLockMutex(resource);
123+
}
124+
99125
void NamedMutexStorage::SetError(const std::string& resource,
100126
const client::ApiError& error) {
101127
impl_->SetError(resource, error);
@@ -112,14 +138,17 @@ NamedMutex::NamedMutex(NamedMutexStorage& storage, const std::string& name,
112138
context_{context},
113139
is_locked_{false},
114140
name_{name},
115-
mutex_{storage_.AquireLock(name_)} {}
141+
mutex_{storage_.AcquireLock(name_)},
142+
lock_condition_{storage_.GetLockCondition(name_)},
143+
lock_mutex_{storage_.GetLockMutex(name_)} {}
116144

117145
NamedMutex::~NamedMutex() { storage_.ReleaseLock(name_); }
118146

119147
void NamedMutex::lock() {
120-
while (!is_locked_ && !context_.IsCancelled()) {
121-
is_locked_ = mutex_.try_lock();
122-
std::this_thread::yield();
148+
if (!context_.IsCancelled() && !try_lock()) {
149+
std::unique_lock<std::mutex> unique_lock{lock_mutex_};
150+
lock_condition_.wait(unique_lock,
151+
[&] { return context_.IsCancelled() || try_lock(); });
123152
}
124153
}
125154

@@ -129,6 +158,7 @@ void NamedMutex::unlock() {
129158
if (is_locked_) {
130159
mutex_.unlock();
131160
is_locked_ = false;
161+
lock_condition_.notify_all();
132162
}
133163
}
134164

olp-cpp-sdk-dataservice-read/src/repositories/NamedMutex.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#pragma once
2121

22+
#include <condition_variable>
2223
#include <memory>
2324
#include <mutex>
2425
#include <string>
@@ -42,9 +43,12 @@ class NamedMutexStorage {
4243
public:
4344
NamedMutexStorage();
4445

45-
std::mutex& AquireLock(const std::string& resource);
46+
std::mutex& AcquireLock(const std::string& resource);
4647
void ReleaseLock(const std::string& resource);
4748

49+
std::condition_variable& GetLockCondition(const std::string& resource);
50+
std::mutex& GetLockMutex(const std::string& resource);
51+
4852
/**
4953
* @brief Saves an error to share it among threads.
5054
*
@@ -112,6 +116,8 @@ class NamedMutex final {
112116
bool is_locked_;
113117
std::string name_;
114118
std::mutex& mutex_;
119+
std::condition_variable& lock_condition_;
120+
std::mutex& lock_mutex_;
115121
};
116122

117123
} // namespace repository

0 commit comments

Comments
 (0)