I'm following the tutorial (already in lesson 16), and I'm missing some advanced background information on how threads are scheduled in Bela, how to write thread safe code, how to write IO code (networking for example) that interact with the audio main thread, etc.
Where I can find more information on this subject?

    there's some detail here https://forum.bela.io/d/853-cannot-read-data-sent-over-serial-port/5
    and I hoped we had much more somewhere, but an extensive search didn't produce the results I expected.

    uzi_hs how threads are scheduled in Bela,

    the audio thread is a Xenomai thread scheduled with priority 95. That should be the highest priority thread on the board. You can schedule auxiliary threads the "usual" way (using e.g.: std::thread or pthread_create()), or using Bela's AuxiliaryTask API: http://docs.bela.io/group__auxtask.html. The advantages of AuxiliaryTask are:

    • these are Xenomai threads, so they can perform with real-time priority ( above Linux priority, but below the audio thread), so they can be used e.g.: for DSP co-routines (see e.g.: Audio/FFT-phase-vocoder). They also have access to Xenomai functions, so they can lock a Xenomai mutex or write to the RT side of a Xenomai pipe (see Pipe below).
    • the API to create/destroy is simpler than pthread and it cleans up after itself automatically so there is no need to manually call the equivalent of std::thread::join or pthread_join().
    • they can be scheduled safely and simply from the audio thread (via Bela_scheduleAuxiliaryTask()), without need to create a mutex or condition variable

    In many cases, we use them for disk or other peripheral I/O, see e.g.:

    Multichannel/multichannel-player
    terminal-only/filter-FIR
    terminal-only/samples
    terminal-only/filter-IIR
    Audio/FFT-phase-vocoder
    Audio/sample-streamer
    Audio/sample-streamer-multi
    Communication/SPI
    Communication/Serial

    or for logging to console large chunks of text without bothering the audio thread, e.g.:

    Capelets/multiplexer-spectrum
    Extras/measure-noisefloor
    Extras/cpu-monitoring

    Writing thread safe code depends on the application. In our examples, we often communicate via a 32-bit shared variable between the two threads. This is simple but often effective, though its timing is not guaranteed and in principle you could encounter some edge cases where the behaviour is not deterministic (e.g.: thread 1 sets some data and then a flag variable, but thread 2 sees the updated flag variable before the data set by thread 1 has been properly updated in memory). In many cases this is not a major issue, but in some it may be crucial. When we are reading data from Trill sensors we simply update a global array containing position and size and then the number of touches. If the number of touches is updated before the global array is updated, you may get some spurious readings when adding or removing one touch, but - again - in many cases these go unnoticed if they at all happen: it all depends on how the code that uses the data reacts to it. For large data structures, you can also share a global pointer and update it from one thread when you want to notify the other thread, although this has the usual issues of not containing a memory barrier, so it's not 100% thread safe, but it may be good enough if a structure in an inconsistent state for a brief moment won't cause noticeable glitches in your program.

    For proper thread-safe operation, we often recommend using the Pipe class, which allows bidirectional communication of large (or small!) chunks of data between two threads (one of which must be a Xenomai thread, i.e.: either the audio thread or a thread created with Bela_{create,run}AuxiliaryTask()), The Pipe can also be blocking, which is useful to avoid spurious wakeups when an auxiliary thread only needs to run when new data is available. Examples using it are:

    Communication/Serial
    Communication/OSC-Pipe
    Gui/frequency-response
    Trill/general-settings

    Other alternatives for proper thread-safe signalling: lightweight C++11 atomics, or more heavy-handed Xenomai mutex (see https://forum.bela.io/d/2622-what-mutex-to-use-on-auxiliarytask/2 ) .