Mark3 Realtime Kernel
lab3_round_robin/main.cpp

This example demonstrates how to use round-robin thread scheduling with multiple threads of the same priority.

/*===========================================================================
_____ _____ _____ _____
___| _|__ __|_ |__ __|__ |__ __| __ |__ ______
| \ / | || \ || | || |/ / ||___ |
| \/ | || \ || \ || \ ||___ |
|__/\__/|__|_||__|\__\ __||__|\__\ __||__|\__\ __||______|
|_____| |_____| |_____| |_____|
--[Mark3 Realtime Platform]--------------------------------------------------
Copyright (c) 2012 - 2019 m0slevin, all rights reserved.
See license.txt for more information
===========================================================================*/
#include "mark3.h"
/*===========================================================================
Lab Example 3: using round-robin scheduling to time-slice the CPU.
Lessons covered in this example include:
- Threads at the same priority get timesliced automatically
- The Thread::SetQuantum() API can be used to set the maximum amount of CPU
time a thread can take before being swapped for another task at that
priority level.
Takeaway:
- CPU Scheduling can be achieved using not just strict Thread priority, but
also with round-robin time-slicing between threads at the same priority.
===========================================================================*/
extern "C" {
void __cxa_pure_virtual(void) {}
void DebugPrint(const char* szString_);
}
namespace
{
using namespace Mark3;
//---------------------------------------------------------------------------
// This block declares the thread data for one main application thread. It
// defines a thread object, stack (in word-array form), and the entry-point
// function used by the application thread.
Thread clApp1Thread;
void App1Main(void* unused_);
//---------------------------------------------------------------------------
// This block declares the thread data for one main application thread. It
// defines a thread object, stack (in word-array form), and the entry-point
// function used by the application thread.
Thread clApp2Thread;
void App2Main(void* unused_);
//---------------------------------------------------------------------------
// idle thread -- do nothing
Thread clIdleThread;
void IdleMain(void* /*unused_*/)
{
while (1) {}
}
//---------------------------------------------------------------------------
void App1Main(void* unused_)
{
// Simple loop that increments a volatile counter to 1000000 then resets
// it while printing a message.
volatile uint32_t u32Counter = 0;
while (1) {
u32Counter++;
if (u32Counter == 1000000) {
u32Counter = 0;
Kernel::DebugPrint("Thread 1 - Did some work\n");
}
}
}
//---------------------------------------------------------------------------
void App2Main(void* unused_)
{
// Same as App1Main. However, as this thread gets twice as much CPU time
// as Thread 1, you should see its message printed twice as often as the
// above function.
volatile uint32_t u32Counter = 0;
while (1) {
u32Counter++;
if (u32Counter == 1000000) {
u32Counter = 0;
Kernel::DebugPrint("Thread 2 - Did some work\n");
}
}
}
} // anonymous namespace
using namespace Mark3;
//---------------------------------------------------------------------------
int main(void)
{
// See the annotations in lab1.
clIdleThread.Init(awIdleStack, sizeof(awIdleStack), 0, IdleMain, 0);
clIdleThread.Start();
// In this exercise, we create two threads at the same priority level.
// As a result, the CPU will automatically swap between these threads
// at runtime to ensure that each get a chance to execute.
clApp1Thread.Init(awApp1Stack, sizeof(awApp1Stack), 1, App1Main, 0);
clApp2Thread.Init(awApp2Stack, sizeof(awApp2Stack), 1, App2Main, 0);
// Set the threads up so that Thread 1 can get 4ms of CPU time uninterrupted,
// but Thread 2 can get 8ms of CPU time uninterrupted. This means that
// in an ideal situation, Thread 2 will get to do twice as much work as
// Thread 1 - even though they share the same scheduling priority.
// Note that if SetQuantum() isn't called on a thread, a default value
// is set such that each thread gets equal timeslicing in the same
// priority group by default. You can play around with these values and
// observe how it affects the execution of both threads.
clApp1Thread.SetQuantum(4);
clApp2Thread.SetQuantum(8);
clApp1Thread.Start();
clApp2Thread.Start();
return 0;
}