Add the spinlock mutex
This commit is contained in:
parent
b353703328
commit
f889e9e754
6 changed files with 126 additions and 0 deletions
1
dpf.mk
1
dpf.mk
|
|
@ -101,6 +101,7 @@ SFIZZ_SOURCES = \
|
|||
src/sfizz/simd/HelpersAVX.cpp \
|
||||
src/sfizz/Synth.cpp \
|
||||
src/sfizz/Tuning.cpp \
|
||||
src/sfizz/utility/SpinMutex.cpp \
|
||||
src/sfizz/Voice.cpp \
|
||||
src/sfizz/Wavetables.cpp
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ set (SFIZZ_HEADERS
|
|||
sfizz/Config.h
|
||||
sfizz/Curve.h
|
||||
sfizz/Debug.h
|
||||
sfizz/utility/SpinMutex.h
|
||||
sfizz/utility/SpinMutex.cpp
|
||||
sfizz/effects/impl/ResonantArray.h
|
||||
sfizz/effects/impl/ResonantArrayAVX.h
|
||||
sfizz/effects/impl/ResonantArraySSE.h
|
||||
|
|
|
|||
43
src/sfizz/utility/SpinMutex.cpp
Normal file
43
src/sfizz/utility/SpinMutex.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "SpinMutex.h"
|
||||
#include <atomic_queue/defs.h>
|
||||
#include <thread>
|
||||
|
||||
// based on Timur Doumler's implementation advice for spinlocks
|
||||
|
||||
void SpinMutex::lock() noexcept
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (try_lock())
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (try_lock())
|
||||
return;
|
||||
atomic_queue::spin_loop_pause();
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (int i = 0; i < 3000; ++i) {
|
||||
if (try_lock())
|
||||
return;
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
atomic_queue::spin_loop_pause();
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
28
src/sfizz/utility/SpinMutex.h
Normal file
28
src/sfizz/utility/SpinMutex.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
|
||||
class SpinMutex {
|
||||
public:
|
||||
void lock() noexcept;
|
||||
bool try_lock() noexcept;
|
||||
void unlock() noexcept;
|
||||
|
||||
private:
|
||||
std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
inline bool SpinMutex::try_lock() noexcept
|
||||
{
|
||||
return !flag_.test_and_set(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
inline void SpinMutex::unlock() noexcept
|
||||
{
|
||||
flag_.clear(std::memory_order_release);
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ set(SFIZZ_TEST_SOURCES
|
|||
SemaphoreT.cpp
|
||||
SwapAndPopT.cpp
|
||||
TuningT.cpp
|
||||
ConcurrencyT.cpp
|
||||
)
|
||||
|
||||
add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES})
|
||||
|
|
|
|||
51
tests/ConcurrencyT.cpp
Normal file
51
tests/ConcurrencyT.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "sfizz/utility/SpinMutex.h"
|
||||
#include "catch2/catch.hpp"
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
TEST_CASE("[SpinMutex] Basic synchronization")
|
||||
{
|
||||
constexpr size_t num_threads = 8;
|
||||
constexpr size_t num_iterations = 1000000;
|
||||
|
||||
volatile size_t counter = 0;
|
||||
SpinMutex counter_mutex;
|
||||
|
||||
std::thread threads[num_threads];
|
||||
|
||||
volatile bool ready = false;
|
||||
std::condition_variable ready_cv;
|
||||
std::mutex ready_mtx;
|
||||
|
||||
auto thread_run = [&]()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(ready_mtx);
|
||||
ready_cv.wait(lock, [&]() -> bool { return ready; });
|
||||
lock.unlock();
|
||||
|
||||
for (size_t i = 0; i < num_iterations; ++i) {
|
||||
std::unique_lock<SpinMutex> lock(counter_mutex);
|
||||
++counter;
|
||||
}
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < num_threads; ++i)
|
||||
threads[i] = std::thread(thread_run);
|
||||
|
||||
std::unique_lock<std::mutex> lock(ready_mtx);
|
||||
ready = true;
|
||||
ready_cv.notify_all();
|
||||
lock.unlock();
|
||||
|
||||
for (unsigned i = 0; i < num_threads; ++i)
|
||||
threads[i].join();
|
||||
|
||||
REQUIRE(counter == num_threads * num_iterations);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue