信号#
信号就像⼀个紧急电话。如果你想让你的朋友注意到某件重要的事情,可以打电话通知他。朋友接到电话(信号)后,便可以⽴即采取⾏动或处理相关事宜。
信号的⼯作机制#
发送信号:线程可以向另⼀个线程发送信号。可以让⽬标线程⽴即中断当前⼯作,转⽽处理信号事件。
处理信号:⽬标线程需要先安装信号处理函数,收到信号时会执⾏相应的处理操作
1. rt_sem_create
用于动态创建信号量。
rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag);参数说明:
name:信号量的名字(可以为RT_NULL表示匿名信号量)。
value:信号量的初始值,表示信号量当前持有的资源数量(例如初始值为 0 表示等待事件,为 1 表示互斥量,或者更大值表示资源计数)。
flag:
RT_IPC_FLAG_PRIO:优先级等待方式,等待线程按照优先级顺序排列。
RT_IPC_FLAG_FIFO:先入先出等待方式,等待线程按照进入顺序排列。返回值:
成功:返回信号量的句柄
rt_sem_t。失败:返回
RT_NULL。示例:
/* 创建一个初始值为 0 的信号量,用于同步场景 */ rt_sem_t sync_sem = rt_sem_create("sync_sem", 0, RT_IPC_FLAG_PRIO);2. rt_sem_init
用于静态信号量的初始化,一般用于静态分配内存的场景。
rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag);参数说明:
sem:信号量对象的指针(需要预先定义好该信号量结构体)。
name:信号量的名字。
value:信号量的初始值。
flag:IPC 对象的属性标志(同rt_sem_create)。返回值:
成功:返回
RT_EOK。失败:返回相应的错误代码。
示例:
/* 静态信号量定义 */ static struct rt_semaphore static_sem; /* 静态信号量初始化,初始值为1,用于互斥操作 */ rt_sem_init(&static_sem, "static_sem", 1, RT_IPC_FLAG_PRIO);3. rt_sem_take
用于获取信号量,线程会尝试获取信号量,如果信号量的计数值为 0,线程会进入等待状态,直到信号量被释放或超时。
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time);参数说明:
sem:信号量的句柄。
time:超时时间(单位为系统 tick),表示最大等待时间。如果设置为RT_WAITING_FOREVER,线程会一直等待。返回值:
成功:返回
RT_EOK。失败:返回
-RT_ETIMEOUT(超时)或其他错误代码。示例:
/* 线程1等待信号量,直到收到信号 */ rt_sem_take(sync_sem, RT_WAITING_FOREVER);4. rt_sem_release
用于释放信号量,增加信号量的计数值,并唤醒等待该信号量的线程。
rt_err_t rt_sem_release(rt_sem_t sem);参数说明:
sem:信号量的句柄。返回值:
成功:返回
RT_EOK。失败:返回相应的错误代码。
示例:
/* 线程2完成任务后释放信号量,通知线程1 */ rt_sem_release(sync_sem);5. rt_sem_delete
用于删除动态信号量(仅限于
rt_sem_create创建的动态信号量)。rt_err_t rt_sem_delete(rt_sem_t sem);参数说明:
sem:信号量的句柄。返回值:
成功:返回
RT_EOK。失败:返回相应的错误代码。
示例:
/* 删除动态创建的信号量 */ rt_sem_delete(sync_sem);
/*
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-02-06 RT-Thread first version
*/
#include <rtthread.h> // 包含RT-Thread的核心头文件
#define DBG_TAG "main" // 定义日志标签
#define DBG_LVL DBG_LOG // 定义日志级别为普通日志
#include <signal.h> // 包含POSIX信号头文件,用于信号处理
#include <rtdbg.h> // 包含调试日志的头文件
static rt_thread_t thread1; // 定义线程1的句柄
// 线程1的信号处理函数
void thread_signal_handler(int signal)
{
// 打印接收到的信号编号
rt_kprintf("线程1进入信号处理函数处理任务,收到信号:%d...\n", signal);
// signal.h文件中定义了SIGUSR1为30(用户定义信号1)
}
// 线程1的入口函数
void thread_entry1(void *parameter)
{
// 安装信号处理函数
rt_signal_install(SIGUSR1, thread_signal_handler);
// 解除信号阻塞,使线程能够接收信号
rt_signal_unmask(SIGUSR1);
// 打印日志:线程1等待信号
rt_kprintf("线程1等待信号...\n");
// 无限循环
while (1)
{
// 打印日志:线程1正在处理日常任务
rt_kprintf("线程1正在处理日常任务...\n");
// 线程延迟500毫秒
rt_thread_mdelay(500);
}
}
// 主函数
int main(void)
{
// 创建线程1
// 参数说明:
// "thread1": 线程名称
// thread_entry1: 线程入口函数
// RT_NULL: 线程参数
// 1024: 线程栈大小(单位:字节)
// 10: 线程优先级(数值越小,优先级越高)
// 10: 线程时间片
thread1 = rt_thread_create("thread1", thread_entry1, RT_NULL, 1024, 10, 10);
// 如果线程1创建成功,则启动线程1
if (thread1 != RT_NULL)
{
rt_thread_startup(thread1);
}
// 主线程延迟2000毫秒
rt_thread_mdelay(2000);
// 向线程1发送SIGUSR1信号
rt_thread_kill(thread1, SIGUSR1);
// 主函数返回0,表示正常结束
return 0;
}
实现效果:

遇到的问题:
如果不在内核中进行使能,则使用信号的相关函数会报错
