Feedback
Feedback

If you are having issues with the exercises, please create a ticket on DevZone: devzone.nordicsemi.com
Click or drag files to this area to upload. You can upload up to 2 files.

Exercise 2

Time slicing

If you don’t want to worry about creating perfect logic for yielding between equal priority threads, you can enable time slicing.

In this exercise, we will take a close look at time slicing and how it affects the interaction between threads, both of equal and different priorities.

Exercise steps

1. In the GitHub repository for this course, open the base code for this exercise, found in lesson7/fund_less7_exer2 of whichever version directory you are using (v2.x.x or v1.6.0-v1.9.1).

2. As you can see in main.c, the thread’s execution functions neither sleep nor yield.

void thread0(void)
{
	while (1) {
            printk("Hello, I am thread0\n");
            k_busy_wait(1000000);
	}
}

void thread1(void)
{
	while (1) {
            printk("Hello, I am thread1\n");
            k_busy_wait(1000000);
	}
}
C

We now know that the first thread that starts running will block the other one indefinitely. The reason we added k_busy_wait() is to prevent the serial terminal from being flooded by logs. This function call causes the current thread to execute a do-nothing loop for a specified time in microseconds. This function is intended for debugging purposes only and it’s not recommended for production code.

3. To avoid thread0 from starving thread1 which is at the same priority level, let’s enable time slicing in our project, by adding the following lines to the prj.conf file.

CONFIG_TIMESLICING=y
CONFIG_TIMESLICE_SIZE=10
CONFIG_TIMESLICE_PRIORITY=0
Kconfig
  • TIMESLICING enables the time slicing feature.
  • TIMESLICE_SIZE is the maximum time (in ms) that the current running thread has before it is forcefully preempted by the scheduler to allow the other equal priority threads to run.
  • TIMESLICE_PRIORITY is the priority threshold for time slicing, meaning threads with higher priority than this threshold are not subject to time slicing. We set this value to 0. This means priorities (0 to 15) will be affected by time-slicing only when two or more threads exist in one level. It’s always important to remember that time slicing only affect threads with the same priority level.

4. Build the application and flash it on your development kit. Using a serial terminal you should now see the below output:

*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
Hello, I am thread0
Hello, I am thread1
Hello, I am thread0
Hello, I am thread1
Hello, I am thread0
Hello, I am thread1
Hello, I am thread0
Hello, I am thread1
Hello, I am thread0
Hello, I am thread1
Hello, I am thread1

Hello, I am thread0
Hello, I am thread1
Hello, I am thread0
Hello, I am thread1
Hello, I amHello, I am  thread0
thread1
Terminal

The output shows that the scheduler will preempt the running thread after the configured amount of time (10 ms in this case) regardless of what it is doing. We see that the scheduler preempts the threads even though they did not print the whole printk() message. Notice that the new thread will continue to print the message from the same place it was preempted the last time.

The timeline of the activity looks something like below.

Timeline for preemptive time slicing

The scheduler forcefully preempts thread0 after it runs for 10 ms and lets thread1 run for 10 ms after which thread1 is preempted to give time for thread0 again.

It is important to note that the time slice configuration only affects equal priority threads. So what happens when time slicing is enabled and there are no equal priority threads to run after the time slice time expires?

We can find out by increasing the priority (lowering the priority value) of one of the threads.

5. Change the value of THREAD0_PRIORITY to 6 like below, making thread0 a higher priority than thread1.

#define THREAD0_PRIORITY 6
#define THREAD1_PRIORITY 7
C

6. Build the application and flash it on your development kit. Using a serial terminal you should now see from the output that thread0 runs uninterrupted, starving thread1 forever.

Even though the output might not show it, the scheduler still preempts thread0 every 10 ms to check if there are any other equal or higher priority threads in the “Runnable” state. Since the only other thread, thread1, is of lower priority, the scheduler lets thread0 run for another time slice period. Since thread1 will always be of lower priority, thread0 will run forever like this.

The solution for this exercise can be found in the GitHub repository, lesson7/fund_less7_exer2_solution of whichever version directory you are using (v2.x.x or v1.6.0-v1.9.1).

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.