rtthread:信号量
1 信号量
信号量是一种用于管理线程间资源关系的内核对象,线程可以获取或释放它从而达到同步或互斥的目的;
信号量可以运用在多种场合中,形成锁,同步(多个线程可访问同一资源),资源计数等关系,也能方便的用于线程与线程,中断与线程的同步中;
1.1 semaphore 信号量结构体
//rtconfig.h 默认注释掉了define,需要用到的话自己开启; #define RT_USING_SEMAPHORE //rtdef.h #ifdef RT_USING_SEMAPHORE struct rt_semaphore { struct rt_ipc_object parent; /**< inherit from ipc_object */ rt_uint16_t value; /**< value of semaphore. */ }; typedef struct rt_semaphore *rt_sem_t; #endif struct rt_ipc_object { struct rt_object parent; /**< inherit from rt_object */ rt_list_t suspend_thread; /**< threads pended on this resource */ }; struct rt_object { char name[RT_NAME_MAX]; /**< name of kernel object */ rt_uint8_t type; /**< type of kernel object */ rt_uint8_t flag; /**< flag of kernel object */ #ifdef RT_USING_MODULE void *module_id; /**< id of application module */ #endif rt_list_t list; /**< list node of kernel object */ }; typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */ //IPC flags and control command definitions #define RT_IPC_FLAG_FIFO 0x00 /**< FIFOed IPC. 先进先出 */ #define RT_IPC_FLAG_PRIO 0x01 /**< PRIOed IPC. 优先级 */ #define RT_IPC_CMD_UNKNOWN 0x00 /**< unknown IPC command */ #define RT_IPC_CMD_RESET 0x01 /**< reset IPC object */ #define RT_WAITING_FOREVER -1 /**< Block forever until get resource. */ #define RT_WAITING_NO 0 /**< Non-block. */
1.2 rt_sem_create 创建信号量
这个信号量的创建函数还挺简单的嘞,这个信号量信息不多看来很简单;事后也确实很简单;
信号量的flag建议采用RT_IPC_FLAG_PRIO,可以保证线程的实时性;RT_IPC_FLAG_FIFO属于非实时调度,实时性不如优先级flag方式;
//ipc.c rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag) { rt_sem_t sem; RT_DEBUG_NOT_IN_INTERRUPT; /* allocate object */ sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name); if (sem == RT_NULL) return sem; /* init ipc object */ rt_ipc_object_init(&(sem->parent)); /* set init value */ sem->value = value; /* set parent */ sem->parent.parent.flag = flag; return sem; } RTM_EXPORT(rt_sem_create);
1.3 rt_sem_delete 删除信号量
//ipc.c rt_err_t rt_sem_delete(rt_sem_t sem) { RT_DEBUG_NOT_IN_INTERRUPT; RT_ASSERT(sem != RT_NULL); /* wakeup all suspend threads */ rt_ipc_list_resume_all(&(sem->parent.suspend_thread)); /* delete semaphore object */ rt_object_delete(&(sem->parent.parent)); return RT_EOK; } //在rt_object_delete(rt_object_t object)函数中,主要执行了两个操作,一个是rt_list_remove(&object->list),一个是RT_KERNEL_FREE(object); //object是指针,作为变量传递赋值的时候,可不等价于传递地址了吗? //malloc函数在分配地址的时候,会自动先拿出4字节存储分配的内存大小,然后把后面的地址返回; //所以free内存的时候,不需要传入内存大小,free也知道需要释放的内存大小;
1.4 rt_sem_take 获取信号量
//ipc.c 如果当前信号量值大于0,那么信号量值减1,然后就返回继续执行当前线程函数;说明当前线程使用了一个信号量资源; // 如果当前信号量值为0,说明没有信号量资源;那就根据time值判断是否等待; // 如果不等待则直接返回超时函数;如果等待,则将当前线程悬起到suspend_thread,等到有信号量资源的时候再释放; rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time) { register rt_base_t temp; struct rt_thread *thread; RT_ASSERT(sem != RT_NULL); RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent))); /* disable interrupt */ temp = rt_hw_interrupt_disable(); RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n", rt_thread_self()->name, ((struct rt_object *)sem)->name, sem->value)); if (sem->value > 0) { /* semaphore is available */ sem->value --; /* enable interrupt */ rt_hw_interrupt_enable(temp); } else { /* no waiting, return with timeout */ if (time == 0) { rt_hw_interrupt_enable(temp); return -RT_ETIMEOUT; } else { /* current context checking */ RT_DEBUG_IN_THREAD_CONTEXT; /* semaphore is unavailable, push to suspend list */ /* get current thread */ thread = rt_thread_self(); /* reset thread error number */ thread->error = RT_EOK; RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n", thread->name)); /* suspend thread */ rt_ipc_list_suspend(&(sem->parent.suspend_thread), thread, sem->parent.parent.flag); /* has waiting time, start thread timer */ if (time > 0) { RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n", thread->name)); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(temp); /* do schedule */ rt_schedule(); if (thread->error != RT_EOK) { return thread->error; } } } RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent))); return RT_EOK; } RTM_EXPORT(rt_sem_take);
1.5 rt_sem_release 释放信号量
//ipc.c 如果suspend_thread中有等待线程,那么将其恢复,然后rt_schedule, // 让另外一个等待信号量的suspend_thread有了执行权就相当于这里的信号量加1了; // if suspend_thread中没有等待线程,那么当前线程释放了信号量,就把信号量值加1; rt_err_t rt_sem_release(rt_sem_t sem) { register rt_base_t temp; register rt_bool_t need_schedule; RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent))); need_schedule = RT_FALSE; /* disable interrupt */ temp = rt_hw_interrupt_disable(); RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n", rt_thread_self()->name, ((struct rt_object *)sem)->name, sem->value)); if (!rt_list_isempty(&sem->parent.suspend_thread)) { /* resume the suspended thread */ rt_ipc_list_resume(&(sem->parent.suspend_thread)); need_schedule = RT_TRUE; } else sem->value ++; /* increase value */ /* enable interrupt */ rt_hw_interrupt_enable(temp); /* resume a thread, re-schedule */ if (need_schedule == RT_TRUE) rt_schedule(); return RT_EOK; } RTM_EXPORT(rt_sem_release);
1.6 gitee
rtthread_f1demo: 将rtthread nano3.0.3版本移植到stm32f1上; (gitee.com)
2 小结
写demo的时候应该单独开个文件来写的,这样就不用每次都修改main函数了,调用函数例程就叫xx_sample把;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?