Add 07_multithread_rr and 08_thread_control_apis
This commit is contained in:
1 parent
c8fe95e63b
commit
f7ae8d226b
6 files changed
+297
No files matched your search
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project(07_multithread_rr)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
@@ -0,0 +1,12 @@
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_PRINTK=y
|
||||
|
||||
# Enable zephyr timeslicing
|
||||
CONFIG_TIMESLICING=y
|
||||
|
||||
# Set the timeslice lenght in milliseconds
|
||||
CONFIG_TIMESLICE_SIZE=10
|
||||
|
||||
# Timeslicing only applies to threads whose priority is numerically >= this value(e.g. 0)
|
||||
CONFIG_TIMESLICE_PRIORITY=0
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
|
||||
// Define stack size in bytes
|
||||
#define THREAD_1_STACK_SZ 1024
|
||||
#define THREAD_2_STACK_SZ 1024
|
||||
|
||||
// Define priority, lower number = higher prio
|
||||
#define THREAD_1_PRIORITY 5
|
||||
#define THREAD_2_PRIORITY 5
|
||||
|
||||
static void thread_1_function(void *p1, void *p2, void *p3) {
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p1);
|
||||
printk("\r\n---------------[RTOS THREAD] Project----------------\r\n");
|
||||
while(1) {
|
||||
printk("Hello from Thread 1 \r\n");
|
||||
k_msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
static void thread_2_function(void *p1, void *p2, void *p3) {
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p1);
|
||||
printk("\r\n---------------[RTOS THREAD] Project----------------\r\n");
|
||||
while(1) {
|
||||
printk("Hello from Thread 2 \r\n");
|
||||
k_msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
// Statically create the thread and auto-start
|
||||
K_THREAD_DEFINE(
|
||||
thread_1_tid, // Symbolic thread identifier
|
||||
THREAD_1_STACK_SZ,
|
||||
thread_1_function,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
THREAD_1_PRIORITY,
|
||||
0,
|
||||
0 // Start immediately at boot
|
||||
);
|
||||
|
||||
// Statically create the thread and auto-start
|
||||
K_THREAD_DEFINE(
|
||||
thread_2_tid, // Symbolic thread identifier
|
||||
THREAD_2_STACK_SZ,
|
||||
thread_2_function,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
THREAD_2_PRIORITY,
|
||||
0,
|
||||
0 // Start immediately at boot
|
||||
);
|
||||
|
||||
int main(void) {
|
||||
printk("\r\n----- Main Function -----\r\n");
|
||||
while(1){
|
||||
k_sleep(K_FOREVER);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project(08_thread_control_apis)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
@@ -0,0 +1,12 @@
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_PRINTK=y
|
||||
|
||||
# Enable zephyr timeslicing
|
||||
CONFIG_TIMESLICING=y
|
||||
|
||||
# Set the timeslice lenght in milliseconds
|
||||
CONFIG_TIMESLICE_SIZE=10
|
||||
|
||||
# Timeslicing only applies to threads whose priority is numerically >= this value(e.g.0)
|
||||
CONFIG_TIMESLICE_PRIORITY=0
|
||||
@@ -0,0 +1,193 @@
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
|
||||
/* Demonstrated APIs
|
||||
* - k_thread_create() + K_THREAD_STACK_DEFINE() : create threads at runtime
|
||||
* - k_thread_name_set() : name threads for clarity
|
||||
* - k_yield() : voluntarily yield the CPU
|
||||
* - k_msleep() / k_sleep() / k_wakeup() : sleep and wake threads
|
||||
* - k_thread_suspend() / k_thread_resume() : stop and restart a thread
|
||||
* - k_thread_priority_get() / k_thread_priority_set() : inspect/change priority
|
||||
* - k_thread_abort() : permanently terminate a thread
|
||||
*
|
||||
*
|
||||
* What happens at runtime
|
||||
* - Creates two worker threads (A and B) at the *same priority* (to show round-robin).
|
||||
* - A controller thread (slightly higher priority) performs timed actions:
|
||||
* 1) yields (so you see initial fair sharing),
|
||||
* 2) suspends B (A runs alone),
|
||||
* 3) resumes B (sharing resumes),
|
||||
* 4) boosts A's priority (A dominates; B runs only when A sleeps),
|
||||
* 5) lowers A's priority (sharing resumes),
|
||||
* 6) puts B to sleep forever then wakes it with k_wakeup(),
|
||||
* 7) aborts B (permanently ends B).
|
||||
* - Each action prints to UART so you can see the scheduler effects.
|
||||
*/
|
||||
|
||||
#define STACK_SZ 1024
|
||||
#define PRIO_BASE 5
|
||||
|
||||
// -------------------------- Thread A --------------------------
|
||||
|
||||
K_THREAD_STACK_DEFINE(stack_a, STACK_SZ);
|
||||
|
||||
static struct k_thread thread_a;
|
||||
|
||||
static void thread_a_entry(void *p1, void *p2, void *p3) {
|
||||
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
k_thread_name_set(k_current_get(), "A");
|
||||
|
||||
printk("\r\n[START] A: prio=%d (time-sliced peer)\r\n",
|
||||
k_thread_priority_get(k_current_get()));
|
||||
|
||||
while(1) {
|
||||
printk("A: running...\r\n");
|
||||
k_msleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------- Thread B --------------------------
|
||||
|
||||
K_THREAD_STACK_DEFINE(stack_b, STACK_SZ);
|
||||
|
||||
static struct k_thread thread_b;
|
||||
|
||||
static void thread_b_entry(void *p1, void *p2, void *p3) {
|
||||
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
k_thread_name_set(k_current_get(), "B");
|
||||
|
||||
printk("\r\n[START] B: prio=%d (time-sliced peer)\r\n",
|
||||
k_thread_priority_get(k_current_get()));
|
||||
|
||||
while(1) {
|
||||
printk("B: running...\r\n");
|
||||
k_msleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------- Controller Thread ---------------------
|
||||
|
||||
K_THREAD_STACK_DEFINE(stack_ctl, STACK_SZ);
|
||||
|
||||
static struct k_thread thread_ctl;
|
||||
|
||||
static void print_prios(void) {
|
||||
printk("[INFO] prio(A)=%d prio(B)=%d\r\n",
|
||||
k_thread_priority_get(&thread_a),
|
||||
k_thread_priority_get(&thread_b));
|
||||
}
|
||||
|
||||
static void controller_entry(void *p1, void *p2, void *p3) {
|
||||
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
k_thread_name_set(k_current_get(), "CTL");
|
||||
|
||||
printk("[CTL] controller started (prio=%d)\r\n",
|
||||
k_thread_priority_get(k_current_get()));
|
||||
|
||||
// Initial yield so A & B get a turn immediately.
|
||||
printk("[CTL] yield once to let A & B run\r\n");
|
||||
k_yield(); // voluntary yield
|
||||
|
||||
// After 1s, suspend B
|
||||
k_msleep(1000);
|
||||
printk("[CTL] suspend B\r\n");
|
||||
k_thread_suspend(&thread_b);
|
||||
k_msleep(100);
|
||||
print_prios();
|
||||
|
||||
// Resume B
|
||||
printk("[CTL] resume B\r\n");
|
||||
k_thread_resume(&thread_b);
|
||||
k_msleep(100);
|
||||
|
||||
// Boost A priority (A dominates, B only runs when A sleeps)
|
||||
printk("[CTL] raise A priority (from %d to %d)\r\n",
|
||||
k_thread_priority_get(&thread_a), 3);
|
||||
k_thread_priority_set(&thread_a, 3);
|
||||
print_prios();
|
||||
k_msleep(100);
|
||||
|
||||
// Lower A priority back to baseline (sharing resumes)
|
||||
printk("[CTL] lower A priority (to %d)\r\n", PRIO_BASE);
|
||||
k_thread_priority_set(&thread_a, PRIO_BASE);
|
||||
print_prios();
|
||||
k_msleep(100);
|
||||
|
||||
// Put B to sleep "forever", then wake it with k_wakeup()
|
||||
printk("[CTL] ask B to sleep forever; will wake it in 500 ms\r\n");
|
||||
k_thread_suspend(&thread_b);
|
||||
k_msleep(500);
|
||||
printk("[CTL] wake B (resume)\r\n");
|
||||
k_thread_resume(&thread_b);
|
||||
k_msleep(100);
|
||||
|
||||
// Abort B (permanent termination)
|
||||
printk("[CTL] abort B\r\n");
|
||||
k_thread_abort(&thread_b);
|
||||
k_msleep(100);
|
||||
|
||||
// Sleep controller
|
||||
printk("[CTL] A still running; B aborted.\r\n");
|
||||
|
||||
while(1) {
|
||||
k_sleep(K_FOREVER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void start_thread(struct k_thread *tcb,
|
||||
k_thread_stack_t *stack,
|
||||
size_t stack_sz,
|
||||
k_thread_entry_t entry,
|
||||
int prio,
|
||||
const char *name) {
|
||||
|
||||
k_tid_t tid = k_thread_create( // create a new thread
|
||||
tcb, // control block address
|
||||
stack, // stack memory
|
||||
stack_sz, // stack size
|
||||
entry, // entry function
|
||||
NULL, NULL, NULL, // parameters
|
||||
prio, // thread priority
|
||||
0, // special options
|
||||
K_NO_WAIT); // start immediately
|
||||
|
||||
k_thread_name_set(tid, name); // assign a name
|
||||
}
|
||||
|
||||
|
||||
int main(void) {
|
||||
|
||||
printk("\r\n[MAIN] Thread control API project starting...\r\n");
|
||||
|
||||
// Create worker A at base priority (time-sliced peer)
|
||||
start_thread(&thread_a, stack_a, STACK_SZ,
|
||||
thread_a_entry, PRIO_BASE, "A");
|
||||
|
||||
// Create worker B at the same priority (time-sliced peer)
|
||||
start_thread(&thread_b, stack_b, STACK_SZ,
|
||||
thread_b_entry, PRIO_BASE, "B");
|
||||
|
||||
// Create controller at a higher priority
|
||||
start_thread(&thread_ctl, stack_ctl, STACK_SZ,
|
||||
controller_entry, 4, "CTL");
|
||||
|
||||
while(1){
|
||||
k_sleep(K_FOREVER);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user