Skip to content

Commit 3c406ba

Browse files
committed
Improve thread safety of coro::scoped_lock
1 parent 9f5bd9b commit 3c406ba

File tree

2 files changed

+7
-7
lines changed

2 files changed

+7
-7
lines changed

include/coro/mutex.hpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ class scoped_lock
3939
~scoped_lock();
4040

4141
scoped_lock(const scoped_lock&) = delete;
42-
scoped_lock(scoped_lock&& other) : m_mutex(std::exchange(other.m_mutex, nullptr)) {}
42+
scoped_lock(scoped_lock&& other) : m_mutex(other.m_mutex.exchange(nullptr, std::memory_order::acq_rel)) {}
4343
auto operator=(const scoped_lock&) -> scoped_lock& = delete;
4444
auto operator=(scoped_lock&& other) noexcept -> scoped_lock&
4545
{
4646
if (std::addressof(other) != this)
4747
{
48-
m_mutex = std::exchange(other.m_mutex, nullptr);
48+
m_mutex.store(other.m_mutex.exchange(nullptr, std::memory_order::acq_rel), std::memory_order::release);
4949
}
5050
return *this;
5151
}
@@ -67,7 +67,7 @@ class scoped_lock
6767
class coro::mutex* mutex() const noexcept;
6868

6969
private:
70-
class coro::mutex* m_mutex{nullptr};
70+
std::atomic<class coro::mutex*> m_mutex{nullptr};
7171
};
7272

7373
class mutex
@@ -179,12 +179,13 @@ class mutex
179179
template<concepts::executor executor_type>
180180
inline auto scoped_lock::unlock(executor_type& e) -> void
181181
{
182-
if (m_mutex != nullptr)
182+
if (auto mtx = m_mutex.load(std::memory_order::acquire))
183183
{
184184
std::atomic_thread_fence(std::memory_order::release);
185-
m_mutex->unlock(e);
185+
186186
// Only allow a scoped lock to unlock the mutex a single time.
187187
m_mutex = nullptr;
188+
mtx->unlock(e);
188189
}
189190
}
190191

src/mutex.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ scoped_lock::~scoped_lock()
1111

1212
auto scoped_lock::unlock() -> void
1313
{
14-
if (m_mutex != nullptr)
14+
if (auto mtx = m_mutex.load(std::memory_order::acquire))
1515
{
1616
std::atomic_thread_fence(std::memory_order::release);
1717

18-
class coro::mutex* mtx = m_mutex;
1918
// Only allow a scoped lock to unlock the mutex a single time.
2019
m_mutex = nullptr;
2120
mtx->unlock();

0 commit comments

Comments
 (0)