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");
	}
}

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

We now know that the first thread that starts running will block the other one indefinitely.

3. To avoid that, let’s enable time slicing in our project, by adding the following lines to the prj.conf file.

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 a higher priority than this threshold are not subject to time slicing.

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

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

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)

Forgot your password?
Enter your email address, and we will send a link to reset your password.