Final Platform Layer  0.9.6-beta
Threads

Overview

In this section, you will learn the Basics about creating and handling of Threads.
With Threads, you can run multiple pieces of code in parallel.
Threads require the use of Synchronization methods to prevent race conditions.

Creating a Thread

Call fplThreadCreate() with a pointer to callback and a user pointer argument, to create and immediately run a Thread.

void MyThreadProc(const fplThreadHandle *context, void *data) {
// ... do something here
}
void RunMyThread() {
int myData = 42;
fplThreadHandle *thread = fplThreadCreate(MyThreadProc, &myData);
}
Note
The internal Thread resources will be cleaned up automatically after your code has finished running.
Warning
When a Thread has finished running, you cannot use the same fplThreadHandle anymore -> It may be reassigned to another Thread in the future.

Destroying a Thread?

You don't have to manually release the Thread resources, this will be cleaned up automatically when either the Thread ends naturally or when it was terminated forcefully using fplThreadTerminate() .

Warning
Do not call fplThreadTerminate() to stop or release a Thread! Let the thread exit naturally.

Waiting/Joining for Threads to Exit

Wait for a single Thread to Exit

Call fplThreadWaitForOne() with a pointer to fplThreadHandle and a fplTimeoutValue argument, to wait for a single Thread to finish.

// Wait until the thread is finished
// ... or
// Wait at max for 5 seconds to finish the thread
fplThreadWaitForOne(thread, 5000);

Wait for any Thread to Exit

Call fplThreadWaitForAny() to wait until at least for one Thread to finish.

Example, default thread handle array:

fplThreadHandle **threads; // Thread handle array already initialized
// Wait until one of the threads is finished
fplThreadWaitForAny(threads, numOfThreads, sizeof(fplThreadHandle *), FPL_TIMEOUT_INFINITE);
// ... or
// Wait at max for 5 seconds to finish at least one of the threads -> default stride
fplThreadWaitForAny(threads, numOfThreads, sizeof(fplThreadHandle *), 5000);

Example, custom struct with stored thread handle:

typedef struct MyCustomStruct {
int a;
void *ptr;
fplThreadHandle *thread;
short b;
} MyCustomStruct;
MyCustomStruct *customThreads; // Struct array already initialized
fplThreadHandle **firstPointerToThread = &customThreads[0].thread;
// Wait until one of the threads is finished
fplThreadWaitForAny(firstPointerToThread, numOfThreads, sizeof(MyCustomStruct), FPL_TIMEOUT_INFINITE);
// ... or
// Wait at max for 5 seconds to finish at least one of the threads -> default stride
fplThreadWaitForAny(firstPointerToThread, numOfThreads, sizeof(MyCustomStruct), 5000);

Wait for all Threads to Exit

Call fplThreadWaitForAll() to wait for all Threads to be finished.

Example, default thread handle array:

fplThreadHandle **threads; // Thread handle array already initialized
// Wait until all of the threads are finished
fplThreadWaitForAll(threads, numOfThreads, sizeof(fplThreadHandle *), FPL_TIMEOUT_INFINITE);
// ... or
// Wait at max for 5 seconds to finish all threads
fplThreadWaitForAll(threads, numOfThreads, sizeof(fplThreadHandle *), 5000);

Example, custom struct with stored thread handle:

typedef struct MyCustomStruct {
int a;
void *ptr;
fplThreadHandle *thread;
short b;
} MyCustomStruct;
MyCustomStruct *customThreads; // Struct array already initialized
fplThreadHandle **firstPointerToThread = &customThreads[0].thread;
// Wait until all of the threads are finished
fplThreadWaitForAll(threads, numOfThreads, sizeof(MyCustomStruct), FPL_TIMEOUT_INFINITE);
// ... or
// Wait at max for 5 seconds to finish all threads
fplThreadWaitForAll(threads, numOfThreads, sizeof(MyCustomStruct), 5000);

Terminate a thread

Call fplThreadTerminate() with a pointer to fplThreadHandle as an argument, to forcefully terminate a thread.

Note
Using this will almost immediately terminate the thread and releases its resources.
It is safe to call this when a thread is already terminated.

Query the Thread State

Call fplGetThreadState() with a pointer to fplThreadHandle as an argument, to query the current state.
If a thread is stopped or in the process of getting stopped, it will return fplThreadState_Stopped or fplThreadState_Stopping respectively.
If a thread is started or in the process of getting started, it will return fplThreadState_Running or fplThreadState_Starting respectively.

Notes

Note
Your code should always ensure that it will exit eventually. You can use Synchronization methods to achieve this.
It is bad practice to "Terminate" a thread, you should design your code to let threads end naturally.
fplThreadCreate
fpl_platform_api fplThreadHandle * fplThreadCreate(fpl_run_thread_callback *runFunc, void *data)
Creates and starts a thread and returns the handle to it.
FPL_TIMEOUT_INFINITE
#define FPL_TIMEOUT_INFINITE
Infinite timeout constant.
Definition: final_platform_layer.h:4412
fplThreadWaitForAll
fpl_platform_api bool fplThreadWaitForAll(fplThreadHandle **threads, const size_t count, const size_t stride, const fplTimeoutValue timeout)
Wait until all given threads are done running or the given timeout has been reached.
fplThreadHandle
The thread handle structure.
Definition: final_platform_layer.h:4490
fplThreadWaitForOne
fpl_platform_api bool fplThreadWaitForOne(fplThreadHandle *thread, const fplTimeoutValue timeout)
Wait until the given thread is done running or the given timeout has been reached.
fplThreadWaitForAny
fpl_platform_api bool fplThreadWaitForAny(fplThreadHandle **threads, const size_t count, const size_t stride, const fplTimeoutValue timeout)
Wait until one of the given threads is done running or the given timeout has been reached.