OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
audio_spin_mutex.hpp
1#pragma once
2#include <ossia/detail/config.hpp>
3
4#include <ossia/detail/mutex.hpp>
5#include <ossia/detail/yield.hpp>
6
7#include <array>
8#include <atomic>
9#include <thread>
10
11namespace ossia
12{
13// Code adapted from Timur Doumler's great article:
14// https://timur.audio/using-locks-in-real-time-audio-processing-safely
15struct TS_CAPABILITY("mutex") audio_spin_mutex
16{
17 void lock() noexcept TS_ACQUIRE()
18 {
19 // approx. 5x5 ns (= 25 ns), 10x40 ns (= 400 ns), and 3000x350 ns
20 // (~ 1 ms), respectively, when measured on a 2.9 GHz Intel i9
21 constexpr std::array iterations = {5, 10, 3000};
22
23 for(int i = 0; i < iterations[0]; ++i)
24 {
25 if(try_lock())
26 return;
27 }
28
29 for(int i = 0; i < iterations[1]; ++i)
30 {
31 if(try_lock())
32 return;
33
34 ossia_rwlock_pause();
35 }
36
37 while(true)
38 {
39 for(int i = 0; i < iterations[2]; ++i)
40 {
41 if(try_lock())
42 return;
43
44 ossia_rwlock_pause();
45 ossia_rwlock_pause();
46 ossia_rwlock_pause();
47 ossia_rwlock_pause();
48 ossia_rwlock_pause();
49 ossia_rwlock_pause();
50 ossia_rwlock_pause();
51 ossia_rwlock_pause();
52 ossia_rwlock_pause();
53 ossia_rwlock_pause();
54 }
55
56 // waiting longer than we should, let's give other threads
57 // a chance to recover
58 std::this_thread::yield();
59 }
60 }
61
62 bool try_lock() TS_TRY_ACQUIRE(true)
63 {
64 return !locked.load(std::memory_order_relaxed)
65 && !locked.exchange(true, std::memory_order_acquire);
66 }
67
68 void unlock() TS_RELEASE() { locked.store(false, std::memory_order_release); }
69
70private:
71 std::atomic<bool> locked{false};
72};
73}
Definition git_info.h:7