Multithreading

From Nutwiki
Revision as of 17:02, 27 October 2016 by Harald (Talk | contribs) (1 revision imported)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Test Environments

Hardware Comments Nut/OS
4.8.3
Nut/OS
4.8.7
Ethernut 1.3 H OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 2.1 B OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 3.0 E OK
Binaries
Compiler: ARM-GCC 4.3.3
OK
Binaries
Compiler: ARM-GCC 4.3.3

Description

This example demonstrates how to create and run a second thread.

Source Code

<source lang="c">

  1. include <dev/board.h>
  2. include <stdio.h>
  3. include <io.h>
  1. include <sys/thread.h>
  2. include <sys/timer.h>


THREAD(SlowMessages, arg) {

   int times_reported = 0;
   printf("SECOND THREAD:\n\tHello! Thread 2 here. I will be reporting back to you every 10 seconds! Enjoy the demo!\n");
   for (;;) {
       NutSleep(10000);
       times_reported++;
       printf("SECOND THREAD:\n\tMe again, my 10 seconds are over. I have reported %d times now.\n", times_reported);
   }

}


int main(void) {

   unsigned long baud = 115200;
   int times_reported = 0;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   // create our second thread
   NutThreadCreate("Bg", SlowMessages, NULL, 512);
   printf("FIRST THREAD:\n\tHello user, I'm the first thread in this application. I'll be saying hello every 6 seconds.\n");
   for (;;) {
       NutSleep(6000);
       times_reported++;
       printf("FIRST THREAD:\n\tMe again. Nice to meet you, be seeing you in 6 seconds. I have reported %d times now.\n",
              times_reported);
   }
   return 0;

} </source>

Details

You'll probably have noticed the THREAD function macro on the top but let's start the explanation with the main() function.

<source lang="c"> unsigned long baud = 115200; int times_reported = 0;

NutRegisterDevice(&DEV_DEBUG, 0, 0);

freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud); </source>

Set up debug device and allow us to output to it.

<source lang="c"> /* Create our second thread. */ NutThreadCreate("Bg", SlowMessages, NULL, 512); </source>

This is all you have to do to create a second thread. The first parameter is the thread's name, the second is a pointer to the thread function. The third parameter specifies any parameters we want to pass to our thread. In this case we don't need to pass anything here so we specify NULL. The last parameter specifies the stack size of the thread in bytes. This is the most critical value. If it's too small, then our application may crash. If it's too large, we are wasting memory, a scarce resource in most embedded systems. 512 is fine for our simple example.

<source lang="c"> printf("FIRST THREAD:\n\tHello user, I'm the first thread in this application. I'll be saying hello every 6 seconds.\n"); for (;;) {

   NutSleep(6000);
   times_reported++;
   printf("FIRST THREAD:\n\tMe again. Nice to meet you, be seeing you in 6 seconds. I have reported %d times now.\n", times_reported);

} </source>

After creating our second thread, we don't care about it anymore and let it mind it's own business. Here we let the first thread (the main application) print a message every 6 seconds so we see it is still working.

Now for that THREAD function macro:

<source lang="c"> THREAD(SlowMessages, arg) </source>

This looks strikingly similar to a function declaration and it works in almost the same way. The first parameter is the name of our thread function. We'll use this name when we want to run the thread. The second parameter is the name of a void pointer that is passed to the function as an argument. Actually the macro will be extracted to something like

<source lang="c"> void SlowMessages(void* arg) </source>

You may now ask: If it's similar to a function declaration, why not declare it that way? Well, the reason is that the system will enter thread functions in an unusual manner, which often requires specific compiler directives. The THREAD macros hides such dependencies and guarantees, that the same source code will be accepted by all supported compilers and will run on all supported platforms.

<source lang="c"> int times_reported = 0; printf("SECOND THREAD:\n\tHello! Thread 2 here. I will be reporting back to you every 10 seconds! Enjoy the demo!\n"); for (;;) {

   NutSleep(10000);
   times_reported++;
   printf("SECOND THREAD:\n\tMe again, my 10 seconds are over. I have reported %d times now.\n", times_reported);

} </source>

The rest looks almost like the main() but with other messages and a different time. Once the thread starts it will be printing messages every 10 seconds.

That's it. Now both threads can run at the same time.

One final note: This example uses NutSleep to make the threads give up the CPU so other threads can use it. If you don't want your thread to wait but still want to allow other threads with the same or higher priority to take over the CPU, use NutYieldThread(). This is actually the same as NutSleep(0).

Real world systems will usually perform I/O operations or wait for events and automatically release the CPU while waiting for I/O completion or the arrival of an event. Even our simple example uses stdout to print messages. However, as this is associated to DEV_DEBUG, a polling driver which never releases the CPU, it is mandatory for task switching to call either NutSleep(x) or NutYieldThread() in regular intervals.

Anyway, almost all Nut/OS drivers are interrupt driven and in most cases you don't need to worry about multithreading.

Output

<source lang="text"> FIRST THREAD:

       Hello user, I'm the first thread in this application. I'll be saying hel

lo every 6 seconds. SECOND THREAD:

       Hello! Thread 2 here. I will be reporting back to you every 10 seconds!

Enjoy the demo! FIRST THREAD:

       Me again. Nice to meet you, be seeing you in 6 seconds. I have reported

1 times now. SECOND THREAD:

       Me again, my 10 seconds are over. I have reported 1 times now.

FIRST THREAD:

       Me again. Nice to meet you, be seeing you in 6 seconds. I have reported

2 times now. FIRST THREAD:

       Me again. Nice to meet you, be seeing you in 6 seconds. I have reported

3 times now. SECOND THREAD:

       Me again, my 10 seconds are over. I have reported 2 times now.

</source>

See also

External Links





Template:Languages