I read in several of the posts that fmod is not thread safe. The reason stated was that that involves wrapping each call in a critical section which will impact performance. Conclusions was not to call any functions from multiple threads "unless we were prepared to deal with issues that go with this".
This is little vague and seems extreme in its conclusion.
1) Is there a fundamental reason for fmod not being thread-safe (like you using thread specific storage, storing thread-id’s for some reason, manipulating thread-priority of the calling thread)? Or is it simply lack of critical section issue?
2) If I am fine with critical section performance hit, can I simply protect the whole fmod with a critical section and that way ensure that no more then a single thread gains access to fmod?
3) What are the "issues" you mention that arrise from using multiple threads. Are you talking about "using non-thread-safe library from threads is unpredictable, so use it at your own risk", or do you have a list of known side effects that some people might be able to live with?
My point is, I am a professional programmer, and it is the vagueness that worries me… I was planning to have all my sound effects done from one thread, however the background music was going to happen in another. However, if I have to create a third thread to service just fmod and have rather complicated notification mechanism to other threads… This seems like an overkill for such a simple task.
- milutinjovanovic asked 11 years ago
You shouldnt need to multithread fmod. We can protect our own specific functionality with FMOD_NONBLOCKING so that nothing in the main thread actually does block, and therefore you can keep everything in the main thread.
Putting System::update in another thread is pointless for example – it doesnt block any more and uses a minimal amount of cpu time.
[quote="brett":2v2xyn6a]You shouldnt need to multithread fmod. We can protect our own specific functionality with FMOD_NONBLOCKING so that nothing in the main thread actually does block, and therefore you can keep everything in the main thread.
Putting System::update in another thread is pointless for example – it doesnt block any more and uses a minimal amount of cpu time.[/quote:2v2xyn6a]
For the record, my code calls FMOD from the main thread only, as recommended.
That said, I can see a few cases where thread safety could enter the picture. What if I have multiple threads of my own, and each wants to playSound? What if one thread does all playSound calls, but another thread is in charge of updating motion states and wants to own all set3DAttributes calls? What if I’ve discovered an unintentional stall in FMOD code but cannot get a fix before my deadline, and decide to make all calls from a secondary thread to avoid blocking the main?
All those situations should be rightly made thread-safe by us, not by the FMOD team. I just thought it might help mutual understanding to point them out.
[quote="brett":a90wf9vp]You shouldnt need to multithread fmod. We can protect our own specific functionality with FMOD_NONBLOCKING so that nothing in the main thread actually does block, and therefore you can keep everything in the main thread.
Putting System::update in another thread is pointless for example – it doesnt block any more and uses a minimal amount of cpu time.[/quote:a90wf9vp]
That’s a fair point, although I was wondering if there are any plans to make the async load functions thread safe (loads called with flag FMOD_NONBLOCKING). I have my background loader thread that is asked to load FMOD sample data, so the only way it can do so (afaik) is to interact with the main thread (via a load request dispatched to main thread), where EventGroup::loadEvent is then called with FMOD_NONBLOCKING. Once load is complete the background loader thread is signalled and can continue with remaining files. Problems arise if someone is performing a tight yield loop on the resource system, waiting to load everything (and fails to process anything in main thread), resulting in deadlocks. This can be fixed with diligence, but also on level load there might be significant delays between the load request and the main thread getting some execution time to (of course there are ways to overcome this).. Pretty trivial issue, but would save having to treat the FMOD load as a special case in our background file loader thread.
- Jade_Lee answered 11 years ago
Here’s an example of multithreaded calls to FMOD where critical sections aren’t a performance problem:
We have a game thread and a UI thread. The UI thread handles mouse events when using our game as an IDE (Windows UI in MFC). We put big whopping critical sections around the UI entry points to ensure there is no contention. A single critical section is opened and closed from the game thread each frame.
Since UI events are [i:3pv1xuer]rare[/i:3pv1xuer] and not part of regular gameplay, there is essentially [i:3pv1xuer]no[/i:3pv1xuer] performance penalty, and no noticeable "hitch".
If I was forced to make all FMOD calls in the game thread then I’d have to marshal all sound calls from the UI thread to the game thread. That would be a royal pain, and it would be much more CPU-intensive than a critical section!
- esc67 answered 11 years ago
I have been using FMod Ex in a multi-threaded environment for some time now, and it was indeed enough to just use critical sections to make it work.
Without them, crashes could occur when you were using readData in one thread, and closing the sound from another thread for example.
- Adion answered 11 years ago
That doesn’t apply to fmod as a middleware api.
If we just blanketed everything in 1 criticalsection, what if you do a file open which takes 2 seconds in a thread, then do system update in your main thread? The main thread stalls for 2 seconds for no reason.
Another way is use FMOD_NONBLOCKING where it has specific tested code for this reason.
Directsound is thread safe, and we are constantly trying to protect ourselves from framerate hitches, because our software mixer calls something as trivial as DirectSoundBuffer::getCurrentPosition/DirectSoundBuffer::lock/DirectSoundBuffer::unlock, and we get stalls in System::update because we innocently called DirectSound::commitDeferredSettings once a frame even though no directsound hardware buffers were playing!
The stalls were that bad we had to put a check in System::update in the dsound call to return immediately if no directsound hardware buffers are being used, which saves us from the hitches if only software mixing is used (another reason not to use hardware)
How is it vague? It says use FMOD from one thread very strongly – so just use FMOD from one thread.
You answered question one with question 2.
You can wrap functions in criticalsections if you want.
We’ll probably be adding a threadsafe flag in 4.09 dev branch after 4.08 comes out. It’s not something that can just be thrown in there needs to be extensive testing as deadlocks are the biggest issue.
You confused me with the "strong recommendation not to use them from multiple threads". I deal with plenty of libraries, classes etc, which are internally not thread safe, so to use them a critical section guarding them is needed. But people never advised against using them in multiple threads…
But the topic seems resolved now. I am fine with a misunderstanding here and there… If you stumble at other having similar questions, you might want to add a line spelling out the need for the critical setion.
- milutinjovanovic answered 11 years ago
Brett, and all others, you may consider reading this article:
There are some sound ideas in there that may prove to be useful for implementing fast critical sections in FMOD.
Hope this helps!
- CptLucky answered 11 years ago
I just wanted to say that for our purposes, the current design works very well. The emphasis on making the entry points to FMOD non-threadsafe, while decreasing the costs of those calls as much as possible and shifting the computational burden to threads "inside" of FMOD allows us to make sound calls from game logic very easily and in a relatively performant manner without worrying that we might be somehow stalling things unnecessarily.
Anyway, just wanted to speak up for what may be the silent majority
- audiodev answered 11 years ago
Just to clarify, if we just went an wrapped a criticalsection around everything, the resulting performance would be horrendous. It is -not- the cost of the operating system, it is the fact that if you were calling createSound in one thread , and the main thread was calling something that should be free, like Channel::getPosition or System::getCPUUsage, those functions would totally stalled by the createSound! Thats means you would be getting major frame hitches.
This means we can’t just do a blanket critsection approach, resources have to be carefully wrapped and protected with sections that protect each other and not other things, so the process is very compilcated.
[quote="audiodev":1v6px5l1]Anyway, just wanted to speak up for what may be the silent majority :)[/quote:1v6px5l1]
I strongly second that. Let those clients who want multi-thread safety build their own minimalist protection, let FMOD itself remain high-performance for single-threaded callers. That design decision is critical in our acceptance of FMOD. 😀
Please login first to submit.