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.