![]() In this situation, many developers reach for locks, and that’s exactly what we will be looking at in this article. You might be stuck with data structures accessed by multiple threads simultaneously. Unfortunately, not everyone is in the position where they can re-engineer their audio engine to follow this pattern. When done correctly, this will lead to a system that is thread-safe by design, and you will never need locks on the audio thread. Instead of modifying the data structure in-place, the message thread peels off a copy that contains the modification, while the audio thread still looks at the previous version for however long it needs to. This can be achieved using immutable data structures. The correct answer, in my opinion, is to design your audio engine in such a way that this case never occurs. Typically, the audio thread will be traversing that structure to do its work, while another thread might be modifying or re-generating that structure at the same time. The audio thread needs to access a bigger data structure describing some part of the system, such as a std::vector or a directed graph or perhaps a linked list. If you have a stream of objects flowing from one thread to the other, such as MIDI messages, you can use a lock-free single-producer single-consumer FIFO ( boost::spsc_queue is a good implementation).īut sometimes we find ourselves in a more complicated situation. For this, you can use a std::atomic variable, where T is a built-in numeric type such as int or float this will be lock-free on modern platforms. For example, the user might turn a knob, which will update a parameter in your DSP algorithm. ![]() In the simplest case, a single numerical value needs to be shared between threads. So how do we synchronise the audio thread with the rest of our application? This is well known and covered in many articles and talks, such as Ross Bencina’s seminal article, my own CppCon 2015 talk, and more recently a brilliant series of talks by Dave Rowland and Fabian Renn-Giles ( part 1, part 2). This includes waiting on a mutex, which not only blocks the audio thread but also leads to priority inversion. It is therefore commonly taught that you cannot do anything on the audio thread that might block the thread or otherwise take an unknown amount of time, such as allocating memory, performing any system call, or doing any I/O. If your process does not compute its audio output and write it into the provided buffer before this deadline, you will get an audible glitch, rendering your product worthless for professional use. A common default setting is a buffer size of 128 samples at a sample rate of 44,100 Hz, which translates to 2.9 ms in between callbacks. The time between subsequent audio processing callbacks is typically between 1-10 ms. ![]() The above method also makes your critical sections very short because all you do while the mutex is locked is std::list splicing, which is just a few pointer modifications.Īlternatively, just use concurrent_bounded_queue class from Intel® Threading Building Blocks.When developing music software, you are operating under tight time constraints.
0 Comments
Leave a Reply. |
Details
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |