How to create a thread

Creating a new thread is the most common development task when using an RTOS, this is how it is done in ChibiOS/RT.

Default Threads

After initializing ChibiOS/RT using chSysInit() two threads are spawned by default:

  • Idle thread. This thread has the lowest priority in the system so it runs only when the other threads in the system are sleeping. This threads usually switches the system in a low power mode and does nothing else.
  • Main thread. This thread executes your main() function at startup. The main thread is created at the NORMALPRIO level but it can change its own priority if required. It is from the main thread that the other threads are usually created.

Thread Classes

There are two classes of threads in ChibiOS/RT:

  • Static Threads. This class of threads are statically allocated in memory at compile time.
  • Dynamic Threads. Threads created by allocating memory at run time from a memory heap or a memory pool.
Creating a Static Thread

In order to create a static thread a working area must be declared using the macro THD_WORKING_AREA as shown:

static THD_WORKING_AREA(myThreadWorkingArea, 128);

This macro reserves 128 bytes of stack for the thread and space for all the required thread related structures. The total size and the alignment problems are handled inside the macro, you only need to specify the pure and simple desired stack size.

A static thread can be started by invoking chThdCreateStatic() as shown in this example:

  thread_t *tp = chThdCreateStatic(myThreadWorkingArea,
                                   sizeof(myThreadWorkingArea),
                                   NORMALPRIO,  /* Initial priority.    */
                                   myThread,    /* Thread function.     */
                                   NULL);       /* Thread parameter.    */

The variable tp receives a pointer to the thread object, this pointer is often taken as parameter by other APIs. Now a complete example:

/*
 * My simple application.
 */
 
#include <ch.h>
 
/*
 * Working area for the LED flashing thread.
 */
static THD_WORKING_AREA(myThreadWorkingArea, 128);
 
/*
 * LED flashing thread.
 */
static THD_FUNCTION(myThread, arg) {
 
  while (true) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
  }
}
 
int main(int argc, char *argv[]) {
 
  /* Starting the flashing LEDs thread.*/
  (void)chThdCreateStatic(myThreadWorkingArea, sizeof(myThreadWorkingArea),
                          NORMALPRIO, myThread, NULL);
  .
  .
  .
}

Note that the memory allocated to myThread() is statically defined and cannot be reused. Static threads are ideal for safety applications because there is no risk of a memory allocation failure because progressive heap fragmentation.

Creating a Dynamic Thread using the Heap Allocator

Creating a thread from a memory heap is very easy:

  thread_t *tp = chThdCreateFromHeap(NULL,          /* NULL = Default heap. */
                                     THD_WORKING_AREA_SIZE(128), /* Stack.   */
                                     NORMALPRIO,    /* Initial priority.    */
                                     myThread,      /* Thread function.     */
                                     NULL);         /* Thread parameter.    */

The memory is allocated from the specified heap and the thread is started. Note that the memory is not freed when the thread terminates but when the thread final status is collected by the spawning thread. For example:

/*
 * My simple application.
 */
 
#include <ch.h>
 
/*
 * LED flashing thread.
 */
static THD_FUNCTION(myThread, arg) {
 
  unsigned i = 10;
  while (i > 0) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
    i--;
  }
  chthdExit((msg_t)i);
}
 
int main(int argc, char *argv[]) {
 
  thread_t *tp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(128),
                                     NORMALPRIO+1, myThread, NULL);
  if (tp == NULL)
    chSysHalt("out of memory");
 
  /* The main thread continues its normal execution.*/
  .
  .
  /*
   * Now waits for the spawned thread to terminate (if it has not terminated
   * already) then gets the thread exit message (msg) and returns the
   * terminated thread memory to the heap (default system heap in this
   * example).
   */
  msg_t msg = chThdWait(tp);
  .
  .
}
Creating a Dynamic Thread using the Pool Allocator

A pool is a collection of equally sized memory blocks, creating a thread from a memory pool is very similar to the previous example but the memory of terminated threads is returned to the memory pool rather than to a heap:

/*
 * My simple application.
 */
 
#include <ch.h>
 
/*
 * LED flashing thread.
 */
static THD_FUNCTION(myThread, arg) {
 
  unsigned i = 10;
  while (i > 0) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
    i--;
  }
  chthdExit((msg_t)i);
}
 
int main(int argc, char *argv[]) {
 
  thread_t *tp = chThdCreateFromMemoryPool(myPool, NORMALPRIO+1,
                                           myThread, NULL);
  if (tp == NULL)
    chSysHalt("pool empty");
 
  /* The main thread continues its normal execution.*/
  .
  .
  /*
   * Now waits for the spawned thread to terminate (if it has not terminated
   * already) then gets the thread exit message (msg) and returns the
   * terminated thread memory to the original memory pool.
   */
  msg_t msg = chThdWait(tp);
  .
  .
}

More articles and guides are available on the technical wiki.

learn more

Need Tutorials?

Try the video tutorials and guides on Play Embedded.

learn more

Need Support?

The forums is the best place, registration required.

learn more