第6章:线程间通信(IPC)基础
信号量是Zephyr RTOS中最基本的线程间同步机制之一,用于控制对共享资源的访问或线程间的同步。
/* 初始化信号量 */
void k_sem_init(struct k_sem *sem, unsigned int initial_count, unsigned int limit);
/* 获取信号量 */
int k_sem_take(struct k_sem *sem, k_timeout_t timeout);
/* 释放信号量 */
void k_sem_give(struct k_sem *sem);
/* 重置信号量 */
void k_sem_reset(struct k_sem *sem);
#include <zephyr.h>
#include <sys/printk.h>
struct k_sem my_sem;
void thread_a(void *p1, void *p2, void *p3) {
while (1) {
printk("Thread A waiting for semaphore\n");
k_sem_take(&my_sem, K_FOREVER);
printk("Thread A got semaphore\n");
k_sleep(K_MSEC(1000));
k_sem_give(&my_sem);
printk("Thread A released semaphore\n");
}
}
void thread_b(void *p1, void *p2, void *p3) {
while (1) {
printk("Thread B waiting for semaphore\n");
k_sem_take(&my_sem, K_FOREVER);
printk("Thread B got semaphore\n");
k_sleep(K_MSEC(500));
k_sem_give(&my_sem);
printk("Thread B released semaphore\n");
}
}
void main(void) {
k_sem_init(&my_sem, 1, 1); // 二进制信号量(互斥信号量)
k_thread_create(&thread_a_data, thread_a_stack,
K_THREAD_STACK_SIZEOF(thread_a_stack),
thread_a, NULL, NULL, NULL,
THREAD_A_PRIORITY, 0, K_NO_WAIT);
k_thread_create(&thread_b_data, thread_b_stack,
K_THREAD_STACK_SIZEOF(thread_b_stack),
thread_b, NULL, NULL, NULL,
THREAD_B_PRIORITY, 0, K_NO_WAIT);
}
互斥量是专门设计用于保护共享资源的同步原语,具有所有权概念,只有获取互斥量的线程才能释放它。
/* 初始化互斥量 */
void k_mutex_init(struct k_mutex *mutex);
/* 锁定互斥量 */
int k_mutex_lock(struct k_mutex *mutex, k_timeout_t timeout);
/* 解锁互斥量 */
int k_mutex_unlock(struct k_mutex *mutex);
#include <zephyr.h>
#include <sys/printk.h>
struct k_mutex shared_mutex;
int shared_counter = 0;
void increment_thread(void *p1, void *p2, void *p3) {
while (1) {
k_mutex_lock(&shared_mutex, K_FOREVER);
shared_counter++;
printk("Counter: %d\n", shared_counter);
k_mutex_unlock(&shared_mutex);
k_sleep(K_MSEC(100));
}
}
void decrement_thread(void *p1, void *p2, void *p3) {
while (1) {
k_mutex_lock(&shared_mutex, K_FOREVER);
shared_counter--;
printk("Counter: %d\n", shared_counter);
k_mutex_unlock(&shared_mutex);
k_sleep(K_MSEC(150));
}
}
void main(void) {
k_mutex_init(&shared_mutex);
k_thread_create(&inc_thread_data, inc_thread_stack,
K_THREAD_STACK_SIZEOF(inc_thread_stack),
increment_thread, NULL, NULL, NULL,
PRIORITY, 0, K_NO_WAIT);
k_thread_create(&dec_thread_data, dec_thread_stack,
K_THREAD_STACK_SIZEOF(dec_thread_stack),
decrement_thread, NULL, NULL, NULL,
PRIORITY, 0, K_NO_WAIT);
}
| 特性 | 信号量 (k_sem) | 互斥量 (k_mutex) |
|---|---|---|
| 所有权 | 无所有权概念,任何线程都可以释放 | 有所有权,只有获取锁的线程才能释放 |
| 计数 | 可以有多个计数 | 只能是0或1(锁定/未锁定) |
| 优先级继承 | 不支持 | 支持(可配置) |
| 使用场景 | 线程同步、资源计数 | 保护临界区、共享资源访问 |
| 性能 | 通常更快 | 由于优先级继承可能稍慢 |
优先级继承是互斥量的一个重要特性,用于解决优先级反转问题。当高优先级线程因等待低优先级线程持有的锁而被阻塞时,低优先级线程会临时继承高优先级线程的优先级。
优先级反转是指高优先级线程因为等待低优先级线程释放资源而被阻塞,而低优先级线程又可能被中等优先级线程抢占,导致高优先级线程长时间得不到执行。
Zephyr RTOS的互斥量默认启用了优先级继承机制。当高优先级线程尝试获取已被低优先级线程锁定的互斥量时:
#include <zephyr.h>
#include <sys/printk.h>
#define LOW_PRIORITY 5
#define MEDIUM_PRIORITY 3
#define HIGH_PRIORITY 1
struct k_mutex shared_mutex;
void low_priority_thread(void *p1, void *p2, void *p3) {
printk("Low priority thread started\n");
k_mutex_lock(&shared_mutex, K_FOREVER);
printk("Low priority thread acquired mutex\n");
// 模拟长时间持有锁
for (int i = 0; i < 5; i++) {
printk("Low priority thread working (%d/5)\n", i+1);
k_sleep(K_MSEC(500));
}
k_mutex_unlock(&shared_mutex);
printk("Low priority thread released mutex\n");
}
void medium_priority_thread(void *p1, void *p2, void *p3) {
printk("Medium priority thread started\n");
while (1) {
printk("Medium priority thread running\n");
k_sleep(K_MSEC(300));
}
}
void high_priority_thread(void *p1, void *p2, void *p3) {
k_sleep(K_MSEC(100)); // 确保低优先级线程先获取锁
printk("High priority thread started\n");
printk("High priority thread trying to acquire mutex\n");
k_mutex_lock(&shared_mutex, K_FOREVER);
printk("High priority thread acquired mutex\n");
k_mutex_unlock(&shared_mutex);
printk("High priority thread released mutex\n");
}
void main(void) {
k_mutex_init(&shared_mutex);
k_thread_create(&low_thread_data, low_thread_stack,
K_THREAD_STACK_SIZEOF(low_thread_stack),
low_priority_thread, NULL, NULL, NULL,
LOW_PRIORITY, 0, K_NO_WAIT);
k_thread_create(&med_thread_data, med_thread_stack,
K_THREAD_STACK_SIZEOF(med_thread_stack),
medium_priority_thread, NULL, NULL, NULL,
MEDIUM_PRIORITY, 0, K_NO_WAIT);
k_thread_create(&high_thread_data, high_thread_stack,
K_THREAD_STACK_SIZEOF(high_thread_stack),
high_priority_thread, NULL, NULL, NULL,
HIGH_PRIORITY, 0, K_NO_WAIT);
}
在某些特殊情况下,可能需要禁用优先级继承。可以通过配置内核选项来实现:
# 在prj.conf文件中
CONFIG_PRIORITY_INHERITANCE=n
扫描二维码访问课程店铺
讲师微信(备用)