Foobar2000:Development:Threads

From Hydrogenaudio Knowledgebase


Thread safety

Programming interfaces of foobar2000 are either main-thread-only, or any-thread.

Refer to documentation in SDK headers of individual method or service to determine which of them it belongs to. If there's no mention of thread safety in the documentation, it means that it can be called from any thread.

In particular, any methods that take an abort_callback& argument are obviously designed for use in worker threads, as main thread blocks the user interface and cannot be aborted.

If you have created an instance of some object, such as file or input_decoder, you should call its methods from one thread. If you must talk to one such object from multiple threads, synchronize access.

When in doubt about whether some API can be called off-main-thread, just try it. Methods that are designed for main thread use only will instantly crash (bugcheck) if called from another thread.

Blocking main thread

Various operations, such as decoding of user's audio files, reading of network resources, reading of album covers, etc, can take a long time and block the calling thread.

Please do not do any of these things from the main thread if you can avoid it.

Create worker threads to do the job, then talk back to main thread using fb2k::inMainThread() when done.

fb2k::splitTask()

A special function exists to spawn detached worker threads that block foobar2000 shutdown (but not foobar2000 user interface) until finished.

Use fb2k::splitTask() to create asynchronous tasks; if you don't provide your own abort_callback, you can get shared one from async_task_manager::get()->get_aborter() that will become signaled when foobar2000 is shutting down.

See SDK/app_close_blocker.h for more information.

Scheduling code to run in main thread

You can defer any code to be executed in foobar2000's main thread using main_thread_callback service. This is commonly used to update the user interface in response to progress/completion of asynchronous tasks.

Instead of using main_thread_callback directly, use fb2k::inMainThread() helper function to queue a function/lambda to be executed in main thread. This function returns immediately without blocking; if you need to wait for your main thread payload to execute, use other means (such as wait for an event).

If called in main thread, fb2k::inMainThread() queues your code to be executed later in main thread. This can be used for an example to escape from the current context, avoiding race conditions when calling other foobar2000 API methods in response to global callbacks.

Another helper, fb2k::inMainThread2(), executes your code synchronously if already in main thread, calls fb2k::inMainThread() otherwise.

Abortability

Various potentially timeconsuming methods take an abort_callback& parameter to allow you to cancel them anytime.

When implementing such function, pass caller's abort_callback& down to any other functions expecting one; poll the object often enough to react to user cancelling the operation without disturbing delays.

In case of user aborting the operation (such as stopping playback, cancelling ReplayGain scan, etc), the abort_callback will become set and the next function to poll it will throw exception_aborted, which then should be handled by the context that owns the abort_callback object.

If you must call a function taking abort_callback& and have no means to abort it, pass fb2k::noAbort, the shared dummy abort_callback object that never becomes aborted.