Sign In | Register |

Threads and Scheduling

A thread is a sequence of programmed instructions that can be scheduled and executed independently by the kernel. The threads provide an abstraction for concurrent execution that ultimately provides a method for multitasking. The kernel schedules CPU time for each of the threads based upon their priority. At any point in the application where a higher priority thread becomes ready to execute, the kernel will switch the CPU to execute the higher priority thread. This method of scheduling threads provides the shortest latency for the highest priority threads.

By default, the kernel will schedule threads to run based upon their priority. A higher priority thread will always receive time on the CPU over that of a lower priority thread. The kernel will interrupt (preempt) a lower priority thread to run a higher priority thread if it becomes signaled to run. This strategy of scheduling ensures that at all times, the highest priority thread will receive the CPU with minimal latency.

Threads that share the same priority are scheduled to run in a round-robin fashion. When each thread executes, it is assigned a 'slice' of processor time in units of kernel ticks. When a thread has consumed its alloted time slice, the kernel will switch execution to any other threads that are of equal priority. The kernel will not return to run the same thread without running each of the other equal priority threads.

Basic Usage

The code snippet below illustrates how to create a thread and have it execute a simple forever loop.

#include "Kernel/kernel_thread.h"
#include <assert.h>

static THREAD thread;                           /* Allocate a thread */

void APP_Example(void)
{
    ALIGNED(8) static BYTE stackmem[384];       /* Allocate the thread's stack memory */
    STATUS status;


    status = THREAD_Create(&thread,             /* Create the thread */
                            stackmem,           /* Provide a pointer to the stack memory for the thread */
                            sizeof(stackmem),   /* Indicate the size (in bytes) of the stack memory */
                            PRIO_NORMAL);       /* Specify the priority for the thread */

    assert(status == SUCCESS);
	
    /* At this point, the thread has been created 
    and exists within the kernel, but it is not 
    alive and executing any code yet. */

    status = THREAD_Start(&thread,              /* Start execution from the thread */
                          APP_ThreadFunction,   /* The function for the thread to execute */
                          NULL);                /* An optional argument to pass into the function */

    assert(status == SUCCESS);
}

void APP_ThreadFunction(void* arg)
{
    for (;;) {                                 /* A forever loop */
        THREAD_Sleep(100);
    }
}

Stopping a Thread

Depending upon the desired functionality of the thread, there are several methods for stopping a thread. For a thread that implements a forever loop, one method uses cooperation from the thread to gracefully exit. A thread can be signaled to exit by using the THREAD_Abort() call. If the thread happens to be blocked upon an object when aborted, the thread will be released with the ERR_ABORTED status code. All subsequent attempts to block the aborted thread will also fail until the thread is restarted.

The code snippet below demonstrates a thread function that performs initialization before entering its forever loop. The thread then supports exiting via the THREAD_Abort() method (by checking THREAD_IsAborted()) and can subsequently perform any clean-up to reverse what it performed when it started.

/* A thread function */
static void APP_Thread(void* arg)
{
    Initialize();                           /* Example of some initialization */

    while (!THREAD_IsAborted()) {           /* Forever loop (until aborted) */
	
        /* Thread-specific code here... */
    }

    /* Only here if THREAD_Abort() was called
    for this thread */

    CleanUp();
}

Use THREAD_Terminate() for a brute force method of stopping a thread. Terminating the thread will cause it to stop execution immediately no matter where it is executing code; even if it happens to be blocked waiting upon another object. This can cause other objects that have references (pointers) to the terminated thread to be in an invalid state.

If a thread desires to stop itself, it can simply exit its entry (start) function. When the thread breaks out from its function, the kernel will be invoked and the thread will be automatically terminated. This feature can be especially helpful when creating run-to-completion style threads. For example, once a thread has been created, it can be started and commanded to execute any function that has the form of the THREADSTART function using THREAD_Start(). The function can do its defined task and can simply exit when it has completed. An application can determine if the thread has completed by checking if the thread is alive using THREAD_IsAlive() or it can block and wait for the thread to complete using THREAD_Join().

After a thread has stopped execution, it still exists within the kernel, only it is no longer considered to be alive. The thread can be started again by calling THREAD_Start(). Use THREAD_Destroy() to completely remove and release a thread from the kernel.

API Reference

STATUS THREAD_Create(THREAD* thread, const CHAR* name, void* stk, UINT32 stksize, PRIORITY prio)
Creates a thread with the specified parameters.
PARAMETERS
thread A pointer to a caller allocated thread to be created and initialized.
name A pointer to a NULL terminated string that represents the name for the thread.
stk A pointer to the start of the memory to be used for the thread stack.
stksize The size in bytes for the thread's stack memory.
prio A priority level for the thread. There are 15-available values and must be one of the following.
PRIO_HIGHER_7 A priority 7 levels above normal.
PRIO_HIGHER_6 A priority 6 levels above normal.
PRIO_HIGHER_5 A priority 5 levels above normal.
PRIO_HIGHER_4 A priority 4 levels above normal.
PRIO_HIGHER_3 A priority 3 levels above normal.
PRIO_HIGHER_2 A priority 2 levels above normal.
PRIO_HIGHER_1 A priority 1 level above normal.
PRIO_NORMAL A normal priority level.
PRIO_LOWER_1 A priority 1 level below normal.
PRIO_LOWER_2 A priority 2 levels below normal.
PRIO_LOWER_3 A priority 3 levels below normal.
PRIO_LOWER_4 A priority 4 levels below normal.
PRIO_LOWER_5 A priority 5 levels below normal.
PRIO_LOWER_6 A priority 6 levels below normal.
PRIO_LOWER_7 A priority 7 levels below normal.
RETURNS
SUCCESS The thread has been created.
ERR_NULLREFERENCE The argument 'thread' or 'stk' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
STATUS THREAD_Start(THREAD* thread, THREADSTART func, void* arg)
Starts execution of a thread at the given entry function.
PARAMETERS
thread A pointer to the thread to be started.
func An application-defined function that represents the starting (entry) point for the thread.
arg (optional) A caller argument to be passed to the given thread function. Can be NULL.
RETURNS
SUCCESS The thread has been started.
ERR_NULLREFERENCE The argument 'thread' or 'func' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_INVALIDOPERATION The thread is already alive and executing a function.
ERR_NOTINITIALIZED The specified thread does not exist within the kernel.
BOOLEAN THREAD_IsAlive(THREAD* thread)
Returns an indication of whether a thread is alive. A thread is considered to be alive if it has been started and it has not exited or has been terminated.
PARAMETERS
thread A pointer to the target thread to be checked for being alive.
RETURNS
TRUE if the thread has been started and has not been stopped or terminated; otherwise FALSE.
STATUS THREAD_Abort(THREAD* thread)
Aborts a thread. Once a thread has been aborted, all blocking calls made by the thread will fail with the ERR_ABORTED status code and any calls to THREAD_Aborted() will return as TRUE.
PARAMETERS
thread A pointer to the thread to be aborted.
RETURNS
SUCCESS The thread has been aborted.
ERR_NULLREFERENCE The argument 'thread' was found to be NULL.
ERR_NOTINITIALIZED The specified thread does not exist within the kernel.
BOOLEAN THREAD_Aborted(void)
Returns an indication of whether the calling thread has been aborted.
PARAMETERS
RETURNS
TRUE if the calling thread has been aborted and should exit; otherwise FALSE.
STATUS THREAD_Join(THREAD* thread, UINT32 timeout)
Blocks the calling thread until a thread terminates.
PARAMETERS
thread A pointer to the thread to wait for termination.
timeout The maximum amount of time, in kernel ticks, to wait for the thread to terminate. Use 0 to return immediately without blocking or use INFINITE to wait indefinitely.
RETURNS
SUCCESS The specified thread has terminated.
ERR_NULLREFERENCE The argument 'thread' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified thread does not exist within the kernel.
ERR_TIMEOUT The specified maximum amount of time has elapsed prior to the thread terminating.
STATUS THREAD_Terminate(THREAD* thread)
Terminates execution of a thread immediately.
PARAMETERS
thread A pointer to the thread to be terminated.
RETURNS
SUCCESS The thread has been terminated.
ERR_NULLREFERENCE The argument 'thread' was found to be NULL.
ERR_NOTINITIALIZED The specified thread does not exist within the kernel.
STATUS THREAD_Destroy(THREAD* thread)
Destroys and removes a thread from the kernel. If the thread is alive, the thread will be terminated.
PARAMETERS
thread A pointer to the thread to be destroyed and removed from the kernel.
RETURNS
SUCCESS The thread has been removed from the kernel.
ERR_NULLREFERENCE The argument 'thread' was found to be NULL.
ERR_INVALIDCONTEXT The operation is not supported from the context of an interrupt service routine (ISR).
ERR_NOTINITIALIZED The specified thread does not exist within the kernel.