2.9 KiB
2.9 KiB
Threading System
Source: src/dusk/thread/
Platform support
Threading currently requires pthreads (DUSK_THREAD_PTHREAD). The
implementation lives in the core thread files and is guarded by that
compile-time flag -- there are no separate per-platform thread
directories.
Thread-local storage uses the THREAD_LOCAL macro, which maps to
__thread when pthreads is available. This is used by the error system
to give each thread its own ERROR_STATE.
Thread lifecycle
Threads follow a strict state machine:
STOPPED -> STARTING -> RUNNING -> STOP_REQUESTED -> STOPPED
threadStart()-- blocking: starts the thread and waits until it reaches RUNNING.threadStop()-- blocking: requests stop and waits until STOPPED.threadStartRequest()-- non-blocking equivalent ofthreadStart.threadStopRequest()-- non-blocking equivalent ofthreadStop.
The thread callback polls threadShouldStop() to know when to exit.
Never kill a thread forcefully -- always let it stop cooperatively.
Thread API
void threadInit(thread_t *thread, errorret_t (*callback)(thread_t *t));
// Initialise; callback is the thread entry point.
errorret_t threadStart(thread_t *thread);
// Start and block until RUNNING.
errorret_t threadStop(thread_t *thread);
// Request stop, block until STOPPED.
void threadStartRequest(thread_t *thread);
void threadStopRequest(thread_t *thread);
// Non-blocking variants.
bool_t threadShouldStop(const thread_t *thread);
// Call from inside the thread callback to know when to exit.
Mutex API (threadmutex.h)
Each threadmutex_t wraps a pthread mutex and a condition variable.
void threadMutexInit(threadmutex_t *mutex);
void threadMutexDispose(threadmutex_t *mutex);
void threadMutexLock(threadmutex_t *mutex);
void threadMutexUnlock(threadmutex_t *mutex);
bool_t threadMutexTryLock(threadmutex_t *mutex);
// Returns true if the lock was acquired; false if already held.
void threadMutexWaitLock(threadmutex_t *mutex);
// Block until signalled (like pthread_cond_wait).
// Must be called while holding the lock.
void threadMutexSignal(threadmutex_t *mutex);
// Wake one waiter.
Usage example
static errorret_t workerCallback(thread_t *t) {
while(!threadShouldStop(t)) {
// do work
}
errorOk();
}
thread_t worker;
threadInit(&worker, workerCallback);
errorChain(threadStart(&worker));
// ... later ...
errorChain(threadStop(&worker));
Thread safety rules
- The error system (
ERROR_STATE) is thread-local -- each thread has its own error state. Do not passerrorret_tacross thread boundaries without copying the message and lines strings first. - Asset loading: the background thread calls
loadAsync; the main thread callsloadSync. Never call GPU or SDL functions from the loader background thread. - Use
assertIsMainThread()/assertNotMainThread()to guard functions that have thread affinity requirements.