Schedulers & Fibers
Schedulers
The DexScheduler is responsible for running work items on a thread.
This is performed by integrating with the threads GMainContext.
The main thread of your application will have a DexMainScheduler as the assigned scheduler.
The scheduler manages callbacks such as work items created with dex_scheduler_push().
You can get the default scheduler for the application’s main thread using dex_scheduler_get_default().
The thread’s scheduler can be retrieved with dex_scheduler_ref_thread_default().
Thread Pool Scheduling
Libdex manages a thread pool which may be retrieved using dex_thread_pool_scheduler_get_default().
The thread pool scheduler will manage a number of threads that is deemed useful based on the number of CPU available.
Work items created from outside of the thread pool are placed into a global queue. Thread pool workers will take items from the global queue when they have no more items to process.
All thread pool workers have a local DexScheduler so use of timeouts and other GSource features continue to work.
If you need to interact with long-blocking API calls it is better to use dex_thread_spawn() rather than a thread pool thread.
Thread pool workers use a work-stealing wait-free queue which allows the worker to push work items onto one side of the queue quickly. Doing so also helps improve cacheline effectiveness.
Fibers
Fibers are a type of stackful co-routine. A new stack is created and a trampoline is performed onto the stack from the current thread.
Use dex_scheduler_spawn() to create a new fiber.
When a fiber calls a dex_await(), similar function, or returns the fiber is suspended and execution returns to the scheduler.
By default, fibers have a 128-kb stack with a guard page at the end. Fiber stacks are pooled so that they may be reused during heavy use.
Fibers are a DexFuture which means you can await the completion of a fiber just like any other future.
Note that fibers are pinned to a scheduler. They will not be migrated between schedulers even when a thread pool is in use.
Stackless Coroutines
Coroutines are a stackless alternative that are still futures managed by the same
DexScheduler. Use dex_scheduler_spawn_coroutine() to create them.
A coroutine function is given a DexCoroutineContext and is expected to
return a DexFuture or suspend by returning NULL.
Stackless coroutines generally have lower memory overhead than fibers when you are mainly waiting on futures between steps.
Use DEX_COROUTINE_BEGIN and DEX_COROUTINE_END when writing
coroutines. Suspend with one of the DEX_COROUTINE_SUSPEND_* helpers.
See Coroutines for more guidance.
Cancellation
Fibers may be cancelled if the fiber has been discarded by all futures awaiting completion. Fibers will always exit through a natural exit point such as a pending “await”. All attempts to await will reject with error once a fiber has been cancelled.
If you want to ignore cancellation of fibers, use dex_future_disown() on the fiber after creation.