| Thread API Function | Description |
|---|---|
| k_thread_create() | Dynamically initializes and creates a Zephyr thread at runtime with a specified stack, entry function, priority, and startup delay |
| K_THREAD_DEFINE() | Statically defines a Zephyr thread at build time, with a specified stack size, entry function, priority, and startup delay |
| k_current_get() | Returns a pointer to the k_tid_t thread identifier of the currently executing Zephyr thread |
| k_thread_name_set() | Assigns a human-readable name to a Zephyr thread for easier debugging and identification |
| k_thread_name_get() | Returns the human-readable name assigned to a specified Zephyr thread |
| k_thread_priority_set() | Changes the priority of an existing Zephyr thread at runtime, affecting its scheduling precedence |
| k_thread_priority_get() | Returns the current scheduling priority of a specified Zephyr thread |
| k_thread_suspend() | Suspends a specified Zephyr thread, preventing it from executing until resumed with k_thread_resume() |
| k_thread_resume() | Resumes a previously suspended Zephyr thread, allowing it to execute again according to its scheduling priority |
| k_thread_abort() | Permanently terminates a specified Zephyr thread, preventing it from executing again |
| k_thread_join() | Blocks the calling thread until the specified Zephyr thread terminates or the timeout expires |
Many embedded applications require multiple tasks to operate independently, such as reading sensors, managing communication, and controlling outputs. Implementing all these operations within a single loop can make the software difficult to maintain and reduce system responsiveness. Threads address these challenges by enabling multiple tasks to execute concurrently, with the RTOS scheduler managing their execution based on scheduling policies and priorities.
A thread created with k_thread_create() is initialized explicitly at runtime. The application provides the thread control structure, stack, entry function, and priority. With K_NO_WAIT , the thread becomes ready to run immediately. This approach offers greater runtime control over thread creation and startup.
A thread declared with K_THREAD_DEFINE() is allocated statically and automatically initialized during system startup. This approach simplifies thread and stack management but offers less flexibility in controlling thread creation at runtime.
k_tid_t thread_id =
k_thread_create(
struct k_thread * new_thread, k_thread_stack_t * stack,
size_t stack_size, k_thread_entry_t entry,
void * p1, void * p2, void * p3,
int prio, uint32_t options, k_timeout_t delay
);
K_THREAD_DEFINE(name, stack_size, entry,
p1, p2, p3,
prio, options, delay); Zephyr schedules runnable threads based on their priorities, with lower numeric values indicating higher priority. Higher-priority threads generally preempt lower-priority threads, ensuring that time-critical tasks receive CPU attention first.

Preemptive scheduling: Suitable for most application threads. The scheduler allows a higher-priority thread to preempt a lower-priority thread as soon as it becomes ready. Preemptive threads use priority values of 0 or higher.
Cooperative scheduling: Suitable for threads requiring uninterrupted execution, such as critical state machines or protocol handlers. A cooperative thread runs until it voluntarily yields or blocks, without being preempted by other threads. Assign a negative priority value to enable this policy.
Time-slicing: Enables fair round-robin execution among equal-priority preemptive threads. Set CONFIG_TIMESLICING=y and configure the time slice using CONFIG_TIMESLICE_SIZE. Without time-slicing, equal-priority threads switch only when the running thread yields, blocks, or is otherwise rescheduled
k_thread_create() is used to dynamically initialize and create a thread at runtime using a preallocated thread control structure (struct k_thread) and stack. k_thread_create() allows developers to create threads during program execution. The function specifies the thread’s entry function, arguments, priority, options, and startup delay. It returns a k_tid_t thread identifier that can be used to manage the thread.
k_tid_t thread_id =
k_thread_create(
struct k_thread * new_thread, k_thread_stack_t * stack,
size_t stack_size, k_thread_entry_t entry,
void * p1, void * p2, void * p3,
int prio, uint32_t options, k_timeout_t delay
);
// ---------------------- Example ----------------------
#define THREAD_A_STACK_SIZE 512
#define THREAD_A_PRIORITY 2
K_THREAD_STACK_DEFINE(thread_a_stack, THREAD_A_STACK_SIZE);
struct k_thread thread_a_data;
void thread_a_entry(void *p1, void *p2, void *p3) {
while(1) {
printk("Thread_A: running\n");
k_sleep(K_MSEC(100));
}
}
k_tid_t thread_a_id =
k_thread_create(&thread_a_data,
thread_a_stack,
K_THREAD_STACK_SIZEOF(thread_a_stack),
thread_a_entry, NULL, NULL, NULL,
THREAD_A_PRIORITY, 0, K_NO_WAIT); K_THREAD_DEFINE() is used to statically define and initialize a thread at compile time. It automatically allocates the thread’s stack and control structure, eliminating the need to call k_thread_create() manually. The macro allows developers to specify the thread’s name (ID), stack size, entry function, arguments, priority, options, and startup delay. Threads with a startup delay of K_NO_WAIT are automatically scheduled during system initialization, while other threads can be configured to start later.
K_THREAD_DEFINE(name, stack_size,
entry, p1, p2, p3,
priority, options, delay);
// ---------------------- Example ----------------------
#define THREAD_A_STACK_SIZE 512
#define THREAD_A_PRIORITY 2
void thread_a_entry(void *p1, void *p2, void *p3) {
while(1) {
printk("Thread_A: running\n");
k_sleep(K_MSEC(100));
}
}
K_THREAD_DEFINE(thread_a_id, THREAD_A_STACK_SIZE,
thread_a_entry, NULL, NULL, NULL,
THREAD_A_PRIORITY, 0, 0); k_current_get() is used to retrieve the thread identifier of the currently executing thread. It returns a k_tid_t value, which is a pointer to the current thread’s control structure (struct k_thread).
k_tid_t k_current_get(void);
// ---------------------- Example ----------------------
void thread_entry(void *p1, void *p2, void *p3) {
k_tid_t thread_id = k_current_get();
printk("Current thread ID: %p\n", (void *)thread_id);
while (1) {
printk("Thread is running\n");
k_msleep(1000);
}
}k_thread_name_set() is used to assign or modify a human-readable name for a thread at runtime.
int k_thread_name_set(k_tid_t thread, const char *str);
// ---------------------- Example ----------------------
k_tid_t thread_id = k_current_get();
k_thread_name_set(thread_id, "WorkerThread");k_thread_name_get() is used to retrieve the human-readable name associated with a thread.
const char *k_thread_name_get(k_tid_t thread);
// ---------------------- Example ----------------------
k_tid_t thread_id = k_current_get();
const char *thread_name = k_thread_name_get(thread_id);
printk("Thread name: %s\n", thread_name ? thread_name : "Unknown");k_thread_priority_set() is used to dynamically change the scheduling priority of an existing thread at runtime. It accepts a thread identifier k_tid_t and a new priority value. In Zephyr, lower numerical priority values represent higher scheduling priorities.
void k_thread_priority_set(k_tid_t thread, int prio);
// ---------------------- Example ----------------------
k_tid_t thread_id = k_current_get();
k_thread_priority_set(thread_id, 3);
int priority = k_thread_priority_get(thread_id);
printk("Updated thread priority: %d\n", priority);k_thread_priority_get() is a Zephyr RTOS API function used to retrieve the current scheduling priority of a specified thread. It accepts a thread identifier k_tid_t and returns the thread’s priority as an integer.
int k_thread_priority_get(k_tid_t thread);
// ---------------------- Example ----------------------
k_tid_t thread_id = k_current_get();
int priority = k_thread_priority_get(thread_id);
printk("Thread priority: %d\n", priority);k_thread_suspend() is used to suspend the execution of a specified thread, preventing it from being scheduled until it is explicitly resumed using k_thread_resume(). The function accepts a thread identifier k_tid_t and does not return a value. Suspending a thread does not terminate it or release its allocated resources. Instead, the thread remains suspended and can continue execution after being resumed.
void k_thread_suspend(k_tid_t thread);
// ---------------------- Example ----------------------
// Suspend current thread
k_thread_suspend(k_current_get());k_thread_resume() is used to resume a thread that was previously suspended using k_thread_suspend(). It accepts a thread identifier k_tid_t and removes the thread’s suspended state, allowing it to become eligible for scheduling. The resumed thread continues execution from where it was suspended rather than restarting its entry function. However, if the thread is still waiting on another condition, such as a semaphore or sleep timeout, it will not execute until that condition is satisfied.
void k_thread_resume(k_tid_t thread);
// ---------------------- Example ----------------------
k_tid_t thread_id;
printk("Resuming worker thread\n");
k_thread_resume(thread_id);k_thread_abort() is used to permanently terminate the execution of a specified thread. It accepts a thread identifier k_tid_t and immediately removes the thread from scheduling, regardless of whether it is running, ready, sleeping, or suspended.
void k_thread_abort(k_tid_t thread);
// ---------------------- Example ----------------------
k_tid_t thread_id;
k_thread_abort(thread_id);k_thread_join() is used to block the calling thread until a specified target thread terminates or a timeout occurs. It accepts a pointer to the target thread’s control structure (struct k_thread) and a timeout value k_timeout_t. The function returns 0 if the target thread has terminated, or a negative error code if the wait fails or times out. Unlike k_thread_abort(), which forcibly terminates a thread, k_thread_join() allows a thread to wait for another thread to complete naturally.
int k_thread_join(struct k_thread *thread, k_timeout_t timeout);
// ---------------------- Example ----------------------
#define STACK_SIZE 1024
#define THREAD_PRIORITY 5
void thread_entry(void *p1, void *p2, void *p3) {
printk("Worker thread started\n");
k_msleep(3000);
printk("Worker thread finished\n");
// Thread terminates automatically upon return
}
K_THREAD_DEFINE(thread_id, STACK_SIZE,
thread_entry, NULL, NULL, NULL,
THREAD_PRIORITY, 0, 0);
int main(void) {
// Wait up to 5 seconds for the worker to finish
int ret = k_thread_join(thread_id, K_SECONDS(5));
if (ret == 0) {
printk("Worker thread successfully terminated\n");
} else if (ret == -EAGAIN) {
printk("Timeout waiting for worker thread\n");
} else {
printk("Thread join failed: %d\n", ret);
}
return 0;
}
[1] Zephyr Project Documentation, Threads
[2] Zephyr Project Documentation, Scheduling
[2] Zephyr Project Documentation, Kernel Timing
Back to top of the page