ThreadX——IPC应用之信号量

发布者:legend9最新更新时间:2025-02-28 来源: cnblogs关键字:ThreadX  信号量 手机看文章 扫描二维码
随时随地手机看文章

一、应用简介

在RTOS的应用开发中,信号量也是经常使用到的一种用于多任务之间信息同步、资源互斥访问的一种手段,常用于协调多个任务访问同一资源的场景。信号量又分为计数信号量和互斥信号量。计数信号量可以表示整体资源数量,当获取一个资源后计数信号量减一,释放一个资源后计数信号量加一,当信号量为0时即表明资源被全部分配导致无法再获取资源,任务可以挂起等待直到有资源可用。互斥信号量是可以理解为只能维护资源数量为1的二值计数信号量(值为0或1),但是互斥信号量又不同于计数信号量,因为它还具有优先级继承的机制(优先级继承机制是RTOS中为了避免出现优先级翻转问题而做的处理方式。简单来说就是如果低优先级持有互斥信号量那么高优先级任务想访问互斥量就会失败而挂起等待互斥量被释放,此时反而是低优先级任务在运行,这就出现了优先级翻转。为了避免该情况RTOS处理方式是把正在持有互斥量运行的低优先级任务的优先级提高到与等待访问互斥资源的高优先级任务同等优先级,这就是优先级继承。等互斥量被释放后RTOS会将该任务恢复到之前的低优先级)。


信号量应用有一个很贴切的举例就是停车场管理。可以把停车场的所有停车位看作计数信号量初始值,当有车辆进入停车场计数信号量值减一,当有车辆离开计数信号量值加一。当值为0时说明没有空车位了,外面车辆无法再停进来,需要等到有空车位出现(计数信号量非0)。停车场中的每一个停车位又可以用互斥信号量来表示,当有车辆占据某车位时表明该车辆持有该车位的互斥信号量,其他车辆无法再停在该车位(如果有人非要杠说万一车位大可以停2个小车那我莫法哈哈哈)。当该车位车辆离开后表明释放该车位的互斥信号量,此时其他车辆可以停入该车位。


二、API简介

下面列出ThreadX中使用信号量常用到的函数


1、创建计数信号量

描述


此服务为线程间同步创建一个计数信号量。初始信号量计数被指定为输入参数


参数


semaphore_ptr 指向信号量控制块的指针

name_ptr 指向信号量名称的指针

initial_count 指定此信号量的初始计数。 合法值的范围是0x00000000至0xFFFFFFFF

返回值


TX_SUCCESS (0x00) 成功创建信号量

TX_SEMAPHORE_ERROR (0x0C) 无效的信号量指针。指针是 NULL 或者已经创建了信号量

TX_CALLER_ERROR (0x13) 该服务的调用者无效

UINT tx_semaphore_create(

    TX_SEMAPHORE *semaphore_ptr,

    CHAR *name_ptr, 

    ULONG initial_count);


2、删除计数信号量

描述


此服务删除指定的计数信号量,恢复所有挂起的等待信号量的线程,并返回TX_DELETED状态。


在删除信号量之前,应用程序必须确保完成(或禁用)此信号量的 put_notify 回调。此外,应用程序必须防止再使用已删除的信号量。


参数


semaphore_ptr 指向先前创建的信号量的指针

返回值


TX_SUCCESS (0x00) 成功删除计数信号量

TX_SEMAPHORE_ERROR (0x0C) 无效的计数信号量指针

TX_CALLER_ERROR (0x13) 该服务的调用者无效


UINT tx_semaphore_delete(TX_SEMAPHORE *semaphore_ptr);


3、获取计数信号量

描述


此服务从指定的计数信号量获取一个信号量,指定的信号量计数减少一个。


参数


semaphore_ptr 指向先前创建的计数信号量的指针

wait_option :TX_NO_WAIT (0x00000000)不等待直接返回获取结果;TX_WAIT_FOREVER (0xFFFFFFFF)一直挂起等待直到获取到信号量;0x00000001 ~ 0xFFFFFFFE指定挂起等待多少个心跳节拍。

返回值


TX_SUCCESS (0x00) 成功获取信号量

TX_DELETED (0x01) 线程挂起时删除了计数信号量

TX_NO_INSTANCE (0x0D) 服务无法检索计数信号量的实例(在指定的等待时间内信号量计数为零)

TX_WAIT_ABORTED (0x1A) 被其他线程或计时器或中断打断而导致服务挂起

TX_SEMAPHORE_ERROR (0x0C) 计数信号量指针无效

TX_WAIT_ERROR (0x04) 在非线程调用中指定了TX_NO_WAIT以外的等待选项

UINT tx_semaphore_get(

    TX_SEMAPHORE *semaphore_ptr,

    ULONG wait_option);


4、获取计数信号量信息

描述


该服务检索有关指定信号量的信息


参数


参数为TX_NULL表示不获取该参数的信息


semaphore_ptr 指向信号量控制块的指针

name 指向信号量名称的指针的目标指针

current_value 指向当前信号量计数的目标的指针

first_suspended 指向这个信号量挂起列表中第一个线程的指针

suspended_count 指向当前挂起在此信号量上的线程数的指针

next_semaphore 指向下一个创建的信号量指针的目标指针

返回值


TX_SUCCESS (0x00) 获取信息成功

TX_SEMAPHORE_ERROR (0x0C) 无效的信号量指针

UINT tx_semaphore_info_get(

    TX_SEMAPHORE *semaphore_ptr,

    CHAR **name, ULONG *current_value,

    TX_THREAD **first_suspended,

    ULONG *suspended_count,

    TX_SEMAPHORE **next_semaphore);


5、增加计数信号量

描述

该服务将指定的信号量计数加一。

如果在信号量为0xFFFFFFFF时调用此服务,则新的put操作将导致信号量重置为零。

参数

semaphore_ptr 指向创建的计数信号量控制块的指针

返回值

TX_SUCCESS (0x00) 成功放置信号量

TX_SEMAPHORE_ERROR (0x0C) 指向信号量的指针无效


UINT tx_semaphore_put(TX_SEMAPHORE *semaphore_ptr);


6、增加指定上限的计数信号量

描述


该服务将指定的计数信号量增加一个。 如果计数信号量的当前值大于或等于指定的上限,则不会增加信号量,并且将返回TX_CEILING_EXCEEDED错误。


参数


semaphore_ptr 指向先前创建的信号量的指针

ceiling 信号量所允许的上限值(有效值范围是1到0xFFFFFFFF)

返回值


TX_SUCCESS (0x00) 操作成功

TX_CEILING_EXCEEDED (0x21) Put请求超过上限

TX_INVALID_CEILING (0x22) 为上限提供了无效值零

TX_SEMAPHORE_ERROR (0x0C) 无效的信号量指针

UINT tx_semaphore_ceiling_put(

    TX_SEMAPHORE *semaphore_ptr,

    ULONG ceiling);


7、创建互斥信号量

描述


此服务为线程间互斥创建互斥体以保护资源。


参数


mutex_ptr 指向互斥量控制块的指针

name_ptr 指向互斥量名称的指针

priority_inherit 指定此互斥对象是否支持优先级继承。 如果此值为TX_INHERIT,则支持优先级继承。 如果指定TX_NO_INHERIT,则此互斥锁不支持优先级继承。

返回值


TX_SUCCESS (0x00) 成功创建信号量

TX_MUTEX_ERROR (0x1C)无效的互斥指针。 指针为NULL或互斥体已创建

TX_CALLER_ERROR (0x13) 该服务的调用者无效

TX_INHERIT_ERROR (0x1F) 无效的优先级继承参数

UINT tx_mutex_create(

    TX_MUTEX *mutex_ptr,

    CHAR *name_ptr, 

    UINT priority_inherit); 


8、删除互斥信号量

描述


该服务将删除指定的互斥信号量。 恢复所有等待互斥的已暂停线程,并返回TX_DELETED返回状态。


应用程序应防止使用已删除的互斥信号量


参数


mutex_ptr 指向先前创建的互斥体的指针

返回值


TX_SUCCESS (0x00) 操作成功

TX_MUTEX_ERROR (0x1C) 无效的互斥体指针

TX_CALLER_ERROR (0x13) 该服务的调用者无效


UINT tx_mutex_delete(TX_MUTEX *mutex_ptr);


9、获取互斥信号量

描述

该服务尝试获取指定互斥锁的独占所有权。 如果调用线程已经拥有互斥锁,则内部计数器将递增,并返回成功状态

如果互斥锁由另一个线程拥有,并且该线程具有更高的优先级,并且在互斥锁创建时指定了优先级继承,则优先级较低的线程的优先级将暂时提高到调用线程的优先级。

拥有互斥量的低优先级线程的优先级在互斥体所有权期间绝对不能由外部线程修改

参数

mutex_ptr 指向先前创建的互斥体的指针

wait_option:TX_NO_WAIT (0x00000000)不等待直接返回获取结果;TX_WAIT_FOREVER (0xFFFFFFFF)一直挂起等待直到获取到信号量;0x00000001 ~ 0xFFFFFFFE指定挂起等待多少个心跳节拍。

返回值

TX_SUCCESS (0x00) 操作成功

TX_DELETED (0x01) 线程暂停时互斥体被删除

TX_NOT_AVAILABLE (0x1D) 服务无法在指定的等待时间内获得互斥锁的所有权

TX_WAIT_ABORTED (0x1A) 被其他线程或计时器或中断打断而导致服务挂起

TX_MUTEX_ERROR (0x1C) 无效的互斥体指针

TX_WAIT_ERROR (0x04) 在非线程调用中指定了TX_NO_WAIT以外的等待选项

TX_CALLER_ERROR (0x13) 该服务的调用者无效

UINT tx_mutex_get(

    TX_MUTEX *mutex_ptr, 

    ULONG wait_option);


10、释放互斥信号量

描述

此服务将释放互斥信号量

如果在创建互斥对象时选择了优先级继承,那么释放线程的优先级将恢复到它最初获得互斥对象所有权时的优先级。在拥有互斥对象期间对释放线程所做的任何其他优先级更改都可能被撤消。

参数

mutex_ptr 指向先前创建的互斥体的指针

返回值

TX_SUCCESS (0x00) 操作成功

TX_NOT_OWNED (0x1E) 互斥对象不归调用者所有

TX_MUTEX_ERROR (0x1C) 无效的互斥体指针

TX_CALLER_ERROR (0x13) 该服务的调用者无效


UINT tx_mutex_put(TX_MUTEX *mutex_ptr);


三、实例演示

该实例用到的硬件资源:一个串口、两个按键、一个LED

创建一个计数信号量,指定数量上限为3,KEY1申请计数信号量,KEY2增加计数信号量

创建一个互斥信号量,用于KEY1、KEY2互斥,即两个按键不能同时按下

创建2个任务,一个用于KEY1任务,一个用于KEY2任务,

#define DEMO_STACK_SIZE         (2 * 1024)

#define DEMO_BYTE_POOL_SIZE     (32 * 1024)


TX_THREAD       thread_0;

TX_THREAD       thread_1;


TX_BYTE_POOL byte_pool_0;

UCHAR memory_area[DEMO_BYTE_POOL_SIZE];


TX_MUTEX tx_semaphore_mutex; // 互斥信号量

TX_SEMAPHORE tx_semaphore_count; // 计数信号量

void tx_application_define(void *first_unused_memory)

{

    UINT status;

    CHAR    *pointer = TX_NULL;


    /* 创建互斥信号量 */

    status = tx_mutex_create(&tx_semaphore_mutex,'tx_semaphore_mutex',TX_NO_INHERIT);

    if (TX_SUCCESS != status)

    {

        // 创建失败处理

    }

    /* 创建计数信号量 */

    status = tx_semaphore_create(&tx_semaphore_count, 'tx_semaphore_count', 3);

    if (TX_SUCCESS != status)

    {

        // 创建失败处理

    }


    /* Create a byte memory pool from which to allocate the thread stacks.  */

    tx_byte_pool_create(&byte_pool_0, 'byte pool 0', memory_area, DEMO_BYTE_POOL_SIZE);


    /* Allocate the stack for thread 0.  */

    tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

    /* Create the main thread.  */

    tx_thread_create(&thread_0, 'thread 0', thread_0_entry, 0,  

                    pointer, DEMO_STACK_SIZE, 

                    1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);


    /* Allocate the stack for thread 1.  */

    tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

    /* Create threads 1  */

    tx_thread_create(&thread_1, 'thread 1', thread_1_entry, 0,  

                    pointer, DEMO_STACK_SIZE, 

                    2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);

}

void    thread_0_entry(ULONG thread_input)

{

    UINT status, key_flag = 0;


    CHAR            *name;

    ULONG           current_value;

    TX_THREAD       *first_suspended;

    ULONG           suspended_count;

    TX_SEMAPHORE    *next_semaphore;


    while(1)

    {

        if (0 == key_flag)

        {

            if (GPIO_PIN_SET == HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin))

            {

                key_flag = 1;

                /*按键按下,获取互斥信号量*/

                status = tx_mutex_get(&tx_semaphore_mutex, TX_NO_WAIT);

                if (TX_SUCCESS == status)

                {

                    /*获取计数信号量*/

                    if (TX_SUCCESS == tx_semaphore_get(&tx_semaphore_count, TX_NO_WAIT))

                    {

                        HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);

                        /*获取计数信号量信息*/

                        tx_semaphore_info_get(&tx_semaphore_count, 

                                            &name, ¤t_value, 

                                            &first_suspended, 

                                            &suspended_count, 

                                            &next_semaphore);

                        printf('key1 pressed, current count semaphore is %drn',(int)current_value);

                    }

                    else

                    {

                        printf('key1 failed to get count semaphorern');

[1] [2]
关键字:ThreadX  信号量 引用地址:ThreadX——IPC应用之信号量

上一篇:嵌入式开发笔记——调试组件SEGGER_RTT
下一篇:ThreadX——IPC应用之事件标志

推荐阅读最新更新时间:2026-03-25 02:15

ThreadX——IPC应用之消息队列
一、应用简介 消息队列是RTOS中常用的一种数据通信方式,常用于任务与任务之间或是中断与任务之间的数据传递。在裸机系统中我们通常会使用全局变量的方式进行数据传递,比如在事件发生后在中断中改变数据和设置标志,然后在主循环中轮询不同的标志是否生效来对全局数据执行不同的操作,执行完毕后清除相关标志。但是这种方式需要不断地轮询标志状态,使得CPU的利用率并不高。而使用RTOS的消息队列则具有任务阻塞机制,当没有需要处理的消息时任务挂起等待消息,此时其他任务占用CPU执行其他操作,当有消息放入队列时任务恢复运行进行消息接收和处理。这种消息处理机制相比裸机而言大大地提高了CPU利用率。 ThreadX的消息队列支持“消息置顶通知”功能,也
[单片机]
<font color='red'>ThreadX</font>——<font color='red'>IPC</font><font color='red'>应用</font>之消息队列
凌华科技推出下一代IPC革新边缘侧行业应用,提供可扩展设计和定制功能模块
支持第12/13 代Intel® Core™ 处理器的MVP-5200 / MVP-6200 AI无风扇模块化计算机 摘要: • 无与伦比的性能:支持第 12/13 代 Intel® Core™ i9/i7/i5/i3 处理器,提供一流的性能。 • 极致的灵活性:模块化和可扩展的设计,提供易于扩展的功能和可选的功能模块,满足特定领域的需求。 • 边缘人工智能就绪平台:内置 GPU 和机器视觉的功能,让凌华科技的MVP-5200 / MVP-6200可以立即部署AI应用。 中国上海 – 2023 年 7月 5日 全球领先的边缘计算解决方案、工业PC和主板提供商,英特尔®合作伙伴联盟钛金会员—
[工业控制]
凌华科技推出下一代<font color='red'>IPC</font>革新边缘侧行业<font color='red'>应用</font>,提供可扩展设计和定制功能模块
Imagination加强ThreadX RTOS对MIPS的支持
Imagination 与 Express Logic 合作扩大 ThreadX RTOS 对 MIPS CPU 的进一步支持 适用于多线程 MIPS interAptiv 内核的 ThreadX/SMP 现已就绪 2013 年 12 月 12 日 —— Imagination Technologies (IMG.L) 和 Express Logic 近日宣布,已扩展 Express Logic 广受欢迎的 ThreadX RTOS (实时操作系统) 对 Imagination MIPS CPU 的支持。采用 MIPS interAptiv CPU 后,进一步延伸了 ThreadX 对各代 MIPS CPU 的支持,从深度嵌入式
[嵌入式]
ucos-ii示例3:互斥型信号量测试
环境: 主机:WIN8 开发环境:MDK4.72 ucgui版本:3.90 ucos版本:ucos-ii mcu: stm32f103VE 说明: 本示例新建一个互斥型信号量,通过此信号量每次只能有1个任务使用资源函数resource 注意: 1.互斥型信号量的创建不能在内核初始化之前 2.互斥型信号量的请求和释放函数只能在同一个任务中执行,如果一个任务请求了信号量,另一个任务释放信号量的操作会失败 3.为了应对信号量导致的不同任务之间的优先级反转,互斥型信号量的创建需要设置一个优先级,且这个优先级必须是尚未使用的,否则会创建失败 效果图: 源码: #define TASK_STK_SIZE 512 /***
[单片机]
ucos-ii示例3:互斥型<font color='red'>信号量</font>测试
UCOS2_STM32_任务间信号量通信(一)_应用实例描述
Ⅰ、写在前面 本文主要讲述UCOS2基于STM32硬件平台下,两个任务之间利用信号量进行通信实现的方法,具体实现原理将在后面文章讲述。 本文主要站在应用的角度来分析信号量通信,与芯片相关的底层这里不过多描述。本文虽然是STM32F1的芯片,但也适合其他芯片的学习(应用层)。 今天提供的工程代码也适用于STM32其他系列芯片(下载我前面移植好的其他系列工程,替换bsp和app下面相关文件就行。 当然,里面LED、按键和串口驱动如果不是对应的引脚,请适当改一下)。 与本文相关的UCOS移植和内核的讲述可以进入我微信公众号“历史消息”查看。 关于本文的更多详情请往下看。 Ⅱ、本文要点 1.软件工程源代码下载 我将今
[单片机]
UCOS2_STM32_任务间<font color='red'>信号量</font>通信(一)_<font color='red'>应用</font>实例描述
ucos-ii示例2:信号量测试
环境: 主机:WIN8 开发环境:MDK4.72 ucgui版本:3.90 ucos版本:ucos-ii mcu: stm32f103VE 说明: 本示例新建一个信号量,task1接收信号量,task2发送信号量。task1时间片为1s/次,task2时间片3s/次。可以看到,因为信号量的关系,task1输出也是3s/次。 注意: 1.信号量的创建不能在内核初始化之前 源码: #define TASK_STK_SIZE 512 /********************************************************************* *
[单片机]
ucos-ii学习笔记——信号量的原理及使用
Created on: 2012-10-7 Author: zhang bin 学习笔记 for ucos-ii PC redesigned by zhang bin 2012-10-7 versions :V-0.1 All Rights Reserved #include INCLUDES.h #define TASK_STK_SIZE 512 char *s1= MyTask ; char *s2= YouTask ; INT8U err; //定义一个错误信息 INT8U y=0; OS_EV
[单片机]
μC/OS-III对信号量的改进
引言 μC/OS是一个基于优先级调度的可剥夺型实时多任务内核。在多任务的实时内核中,信号量是常用的机制,可以用来实现对共享资源的访问、任务之间的通信和同步,以及任务和中断的同步等功能。μC/OS—II中提供了等待和释放信号量等最基本的服务,而在μC/OS—III中,对信号量的使用增加了一些可选的模式,如非阻塞等待、释放但不进行任务调度等,提高了使用的灵活性。更重要的是,在μC/OS—III中还新增了任务内嵌的信号量,用户程序无需建立信号量便可和任务直接通信,比普通信号量更加简单高效。本文将分析对比μC/OS—II和μC/OS—III中信号量内部结构的差异以及μC/OS—III新增的特性。 1 μC/OS—II中信号量内部结构 在μ
[嵌入式]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved