Add 07_multithread_rr and 08_thread_control_apis

This commit is contained in:
hangpersonal committed 2026-10-12 22:24:42 -07:00
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(08_thread_control_apis)
target_sources(app PRIVATE src/main.c)
+12
View File
@@ -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
+193
View File
@@ -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;
}