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/simd/HelpersAVX.cpp \
|
||||||
src/sfizz/Synth.cpp \
|
src/sfizz/Synth.cpp \
|
||||||
src/sfizz/Tuning.cpp \
|
src/sfizz/Tuning.cpp \
|
||||||
|
src/sfizz/utility/SpinMutex.cpp \
|
||||||
src/sfizz/Voice.cpp \
|
src/sfizz/Voice.cpp \
|
||||||
src/sfizz/Wavetables.cpp
|
src/sfizz/Wavetables.cpp
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ set (SFIZZ_HEADERS
|
||||||
sfizz/Config.h
|
sfizz/Config.h
|
||||||
sfizz/Curve.h
|
sfizz/Curve.h
|
||||||
sfizz/Debug.h
|
sfizz/Debug.h
|
||||||
|
sfizz/utility/SpinMutex.h
|
||||||
|
sfizz/utility/SpinMutex.cpp
|
||||||
sfizz/effects/impl/ResonantArray.h
|
sfizz/effects/impl/ResonantArray.h
|
||||||
sfizz/effects/impl/ResonantArrayAVX.h
|
sfizz/effects/impl/ResonantArrayAVX.h
|
||||||
sfizz/effects/impl/ResonantArraySSE.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
|
SemaphoreT.cpp
|
||||||
SwapAndPopT.cpp
|
SwapAndPopT.cpp
|
||||||
TuningT.cpp
|
TuningT.cpp
|
||||||
|
ConcurrencyT.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES})
|
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