New Threads

December 24, 2013

Preemption can make real time system performance prediction difficult.

It is getting difficult to find desktop computers, laptops, and even mobile devices that only have a single CPU in them. In the small embedded space, though, multicore CPUs are an exception — at least for a while longer. However, computers are so fast that even with one CPU they can appear to do more than one thing at a time.

Last time I discussed using Linux or other operating systems in embedded systems. There are a few advantages to doing so, but there are also, of course, disadvantages. One principle advantage of most operating systems is the ability to schedule multiple programs. However, on a small system, that may cause more problems than it solves.

Multiple programs will compete for limited resources. One of those limited resources is the CPU itself. The more programs that run, the more the CPU divides its attention between different tasks. This can also make real time system performance prediction difficult, as well.

Even desktop and server operating systems recognize the relative inefficiency of multitasking multiple processes, and that is why most offer some sort of thread support. A thread is a piece of code that appears to run in parallel with other threads, but doesn’t have as much overhead as a full-blown program. In most operating systems, a thread shares memory and other resources with other threads that belong to the same parent process.

Many lightweight thread libraries don’t actually preempt a running thread (that can add a lot of complexity). Instead, the thread has to do something (directly or indirectly) that it is ready to give up the CPU. This doesn’t require as much overhead and can help when trying to predict performance. You can also do without critical section protection mechanisms and atomic access methods since your threads explicitly release the processor.

If you had a lot of software that ran all the time doing CPU operations, you won’t get good multitasking performance, especially with a system that requires express release of the CPU. But most programs wind up waiting for something: an input from a user or external system, a time to elapse, or an I/O operation to complete. All multitasking systems exploit those waits as an excuse to let some other code take over the CPU.

Some time back, I wrote lwos, which was a “lightweight operating system” that runs on microcontrollers . I did an Arduino port of lwos, but I was wondering what other lightweight threads were available for that platform.

I was aware of a lightweight threading library called protothreads that is used by the (also lightweight) operating system Contiki. I figured there would be a port to Arduino, and I was right.

Keep in mind the threads aren’t really scheduled as in a preemptive system. Each thread is a function, and the protothreads system uses “local continuations” to make the jumps between threads (I’ll talk about the details in an upcoming blog).

Because of the way protothread creates local continuations, you can’t rely on local variables to keep their values after a call that might yield to another thread. If you use the “standard” local continuation, your threads also can’t use the C switch statement, and odd but understandable limitation.

Is there ever a case where you must use threads? No. You can write your own code to do bits of one task and then bits of another. Using threads is just an abstraction that makes your code easier to write and, perhaps more important, easier to read. The advantage to protothreads is it is very lightweight, requiring just some header files and a few extra bytes per thread.

I’ll talk more about protothread and some similar libraries in the next few weeks. But to whet your appetite, here’s a small Arduino program that uses two threads:

#define LC_INCLUDE <lc-addrlabels.h> // use gcc LC
#include <pt.h>

#define LEDPIN 13

// We have two threads
static struct pt pt1, pt2;

void setup()
  while (!Serial);  // wait for Leonardo serial
  pinMode(LEDPIN,OUTPUT);  // set LED
  PT_INIT(&pt1);  // set up threads
  // Set up serial port and write first 
  // numbers
  Serial.print("0, 1, 1, ");

 // Simple function to toggle the LEDs
void toggleLED() 
  static boolean ledstate=false;
  digitalWrite(LEDPIN, ledstate);
// Blink the LED occasionally in this thread
PT_THREAD(led_thread(struct pt *pt, int interval))
  static unsigned long timestamp=0l;
  while (1)

// Compute some Fibonacci numbers
static unsigned int current=1;
static unsigned int prev=1;
static unsigned int t;

PT_THREAD(compute_thread(struct pt *pt))
  while (1)
    // compute next number
  // write it
  Serial.print(", ");
  // Reset after you get one over 100
  if (current>100)
    Serial.println("0, 1, 1, ");
  PT_YIELD(pt);  // Let someone else run

// Arduino "main"
void loop()
  // kick off threads

One thread blinks the onboard LED and the other computes and prints some Fibonacci numbers. These tasks are wholly unrelated, and having them set as separate threads makes the program simple to follow.

I’ll explain more about the program next time. Meanwhile, download the online listings and try it for yourself.