clownaudio icon indicating copy to clipboard operation
clownaudio copied to clipboard

Stop using mutexes

Open Clownacy opened this issue 4 years ago • 5 comments

Apparently using mutexes in an audio callback is a stupid idea, because of stuff like priority-inversion. I never liked using them anyway, since the ones in clownaudio are locked to Windows and POSIX.

Supposedly I should look into lock-free buffers or something. Maybe I can set up a kind of communication system where the main thread only gives commands to the audio callback, instead of modifying shared data - that way, the audio callback is solely-responsible for modifying its private data, avoiding conflicts.

Clownacy avatar Nov 03 '19 21:11 Clownacy

I should probably point out, for future reference, that miniaudio provides a lock-free ring-buffer implementation that might come in handy here.

Clownacy avatar Nov 27 '19 22:11 Clownacy

Arg, apparently miniaudio's lock-free ring buffers aren't for message queues... I wonder what the proper way to go about this is?

Clownacy avatar Dec 13 '19 14:12 Clownacy

I've wondered about that too. Getting data into the callback without locks aren't as straightforward as it seems at first glance

larpon avatar Jan 12 '20 13:01 larpon

So apparently writing a simple lock-free single-consumer/single-producer FIFO is pretty easy, and relatively portable too (the GCC devs claim 'int' is very likely to be atomic).

So, off the top of my head, I could just create a command FIFO, and make the audio thread entirely self-contained - responsible for sound creation, destruction, mixing, etc.

I should probably stop using malloc in that case, since apparently you can't be sure how fast those functions are. A static array of sound slots with a compile-time-configurable size should be fine, instead.

Regarding how exactly the command queue will work, I'm thinking of taking some inspiration from my Mega Drive days - namely the FIFO used by the VDP: each command has an ID, and a tiny data buffer (maybe an int). Any commands that require more than an int's worth of data will be spread across multiple commands, and it will be only the final command in that list that will cause the audio thread to finally process them (think of how you set up a VDP DMA transfer).

Granted, there is one case where the audio thread needs to communicate back to the main thread: the newly-added GetSoundStatus function. However, because this function only returns 0, 1, or -1, I think I can actually safely use a table of atomics, allowing this function to be performed entirely-asynchronously.

Clownacy avatar Mar 03 '20 00:03 Clownacy

Thanks for sharing!

larpon avatar Mar 03 '20 09:03 larpon