都是Semaphore惹得祸

本文记录了一次RTOS系统中HTFDLow中断处理任务无法正常执行的问题排查过程。问题表现为中断正常触发并给予信号量,但处理任务Main_TFDL却未能获取信号量。通过逐步调试与实验,最终定位问题源于另一任务FPGA_FIFO_DAEMON的无限循环,并成功通过调整优先级解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NP向CPU发包,CPU通过中断的方式接收。HTFD High的中断正常,可以调用ISR用来give相应的信号量,Main_TFDH可以take到信号量;HTFD Low的中断也正常,也可正常give信号量,但是Main_TFDL却不能take信号量。调试步骤如下:

1. 利用EZmde由HTFD Low队列发包到CPU,终端显示:

AHE_Isr --- Channel=0    cause reg bit 2 is set
                uqCauseReg=0x00000004    HTFD Low
                send semaphore to Main_TFDL

由此可见,中断确实发生了,但是相应的中断处理任务(Main_TFDL)并没有执行。

 

2. 在终端上查看当前系统中的任务状态:

-> i

NAME        ENTRY       TID    PRI   STATUS      PC       SP     ERRNO DELAY
---------- ------------   -------- ---     ----------    -------- --------   -------       -----
……           ……           ……    …     ……           ……    ……       ……       ……
TFDH_0     Main_TFDH_0   43e6ae0 145 PEND         a25f74 43e6960       0     0
TFDL_0     Main_TFDL_0   43e0860 150 PEND         a25f74 43e06d0       0     0
FPGA_FIFO_Dnp_load_FPGA 43af7d0 150 READY        23df90 43af6e8 3d0001     0
……           ……           ……    …     ……           ……    ……       ……       ……

value = 0 = 0x0

3.查看中断处理任务Main_TFDL的函数调用堆栈:

-> tt 0x43e0860
989800 vxTaskEntry    +54 : Main_TFDL ()
823584 Main_TFDL      +74 : semTake ()
a26a50 semTake        +130: a25df8 ()
value = 0 = 0x0

 

终端处理任务也是正常的。无意间发现FPGA FIFO 溢出检测任务的状态似乎有点不正常,这个任务跟中断处理任务一样,也是需要take相应的信号量才能作相应处理,按理说它的状态也应该是PEND才对,但是此处却是READY。

 

4. 查看FPGA FIFO 溢出检测任务的函数调用堆栈:

-> tt 0x43af7d0
989800 vxTaskEntry    +54 : np_load_FPGA_standby ()
828558 np_load_FPGA_standby+90 : FPGA_check_fifo_overflow ()
242788 FPGA_check_fifo_overflow+20 : BspNPCheckBoard ()
value = 0 = 0x0
-> Main_TFDL -- channel 0 HTFD Low interrupt happen!

HTFD Low Msg queue is empty

 

奇怪的事发生了,tt FPGA FIFO 溢出检测任务后,刚刚没有执行的Main_TFDL现在却得到了执行。NP通过HTFD Low队列向CPU发包,CPU产生中断give信号量,但是Main_TFDL却不能take,但只要一执行

        tt 0x43af7d0 (FPGA FIFO 溢出检测任务)

Main_TFDL就会take到信号量。尝试了好多次,都是这样的结果。

 

5.在代码中去掉FPGA检测任务,重新编译版本,启动后,再从NP向CPU发包。这次中断果然正常了:

AHE_Isr --- Channel=0    cause reg bit 2 is set
                uqCauseReg=0x00000004    HTFD Low
                send semphomore to Main_TFDL

Main_TFDL -- channel 0 HTFD Low interrupt happen!

HTFD Low Msg queue is empty

从以上几步诊断结果来看,问题应该出在FPGA FIFO 溢出检测任务上,但是实在想不通FPGA检测任务怎么会影响到HTFD Low中断处理任务!这两个任务没有共享全局变量,也没有任何进程间通信。

查阅了VxWorks的相关资料,得知ready状态表示任务除了等待CPU外不等待其它资源,执行i命令时此任务是ready状态,那么这个任务有可能平时一直处于无限循环中。

对比了一下创建FPGA FIFO 溢出检测任务和创建HTFD Low中断处理任务的语句,如下:

EZ_TSK_SPAWN( "FPGA_FIFO_DAEMON",
                          NORMAL_PRIORITY_TSK_DEF1/*BELOW_NORMAL_PR_TSK_DEF1*/,
                          ISR_TSK_STK_SIZE_DEF,
                          (EZ_FUNCPTR ) np_load_FPGA_standby,/*lint !e64 */
                           0 );
g_EZisrTaskId[i][1] = EZ_TSK_SPAWN(NP_EZIsrTFDL_Name[i],
                                           NORMAL_PRIORITY_TSK_DEF1,
                                           ISR_TSK_STK_SIZE_DEF,
                                           (EZ_FUNCPTR)NP_EZIsrTFDL_Entry[i],
                                           0);

发现这两个任务处于同一优先级上(NORMAL_PRIORITY_TSK_DEF1)。会不会是FPGA_FIFO_DAEMON 任务中某个地方出错导致了无限循环,而使得处于同一优先级上的HTFD Low中断处理任务得不到执行呢?抱着这个猜想,我把FPGA_FIFO_DAEMON任务的优先级调低(BELOW_NORMAL_PR_TSK_DEF1),如果猜想正确的话,即使FPGA_FIFO_DAEMON任务一直占着CPU进行无限循环,一旦发生HTFD Low中断,高优先级的中断处理任务还是会抢占CPU从而得以执行的。

修改了FPGA_FIFO_DAEMON任务的优先级后,重编版本,下载运行后,果然验证了刚才的猜测。此时只要产生硬件HTFD Low中断,HTFD Low的中断处理任务便立刻被执行。

现在问题已经明朗,问题肯定出在FPGA_FIFO_DAEMON任务中。此任务的入口函数框架如下:

void np_load_FPGA_standby()
{
    ……
    while(TRUE)
    {
        /*每200ms对FPGA的状态进行一次检测*/
        EZ_SEM_TAKE(g_EZPhiId.EZFpgaFifoSem);
       
        /*检查FPGA的FIFO是否溢出*/
        fpga_fifo_state = FPGA_check_fifo_overflow();

        if( fpga_fifo_state && bFPGALoadFlg )
        {
            ……
        }
        ……
    }    
}

按理说此任务不应该一直在循环呀,它需要获得g_EZPhiId.EZFpgaFifoSem这个信号量才可以循环一次,而这个信号量是由时钟中断定时give的。再次检查了时钟中断处理函数,感觉并没有地方出错。请教单位的某老鸟,他问我此信号量有没有初始化,一句话惊醒了梦中人!这个信号在以前的版本是中没有的,是我后加入到v3.5中的,当时只在时钟中断函数中give了一下,在FPGA_FIFO_DAEMON任务中take了一下,还真忘了在NP_Sem_Create()中初始化此信号量。折腾了一天,原来问题出在这,还真有点让人出乎意料。

内容概要:文章基于4A架构(业务架构、应用架构、数据架构、技术架构),对SAP的成本中心和利润中心进行了详细对比分析。业务架构上,成本中心是成本控制的责任单元,负责成本归集与控制,而利润中心是利润创造的独立实体,负责收入、成本和利润的核算。应用架构方面,两者都依托于SAP的CO模块,但功能有所区分,如成本中心侧重于成本要素归集和预算管理,利润中心则关注内部交易核算和获利能力分析。数据架构中,成本中心与利润中心存在多对一的关系,交易数据通过成本归集、分摊和利润计算流程联动。技术架构依赖SAP S/4HANA的内存计算和ABAP技术,支持实时核算与跨系统集成。总结来看,成本中心和利润中心在4A架构下相互关联,共同为企业提供精细化管理和决策支持。 适合人群:从事企业财务管理、成本控制或利润核算的专业人员,以及对SAP系统有一定了解的企业信息化管理人员。 使用场景及目标:①帮助企业理解成本中心和利润中心在4A架构下的运作机制;②指导企业在实施SAP系统时合理配置成本中心和利润中心,优化业务流程;③提升企业对成本和利润的精细化管理水平,支持业务决策。 其他说明:文章不仅阐述了理论概念,还提供了具体的应用场景和技术实现方式,有助于读者全面理解并应用于实际工作中。
<think>嗯,用户问的是“Semaphore是什么”。之前他们问过关于LongAdder的问题,现在转向了另一个并发工具Semaphore。首先需要确认用户的基础,可能是在学习Java并发编程,或者是想了解多线程控制的相关知识。用户可能已经了解过AtomicLong和LongAdder的区别,现在想进一步扩展并发工具的使用场景。 Semaphore是Java中的一个同步工具,用来控制同时访问特定资源的线程数量。用户可能在实际开发中遇到了资源池管理的问题,比如数据库连接池,或者限流的需求。需要解释清楚Semaphore的基本概念,以及它的主要用途。 用户可能想知道Semaphore的工作原理,比如许可证的机制,acquire和release方法的作用。需要详细说明这些方法如何控制线程的访问,可能还需要对比其他同步机制,比如CountDownLatch或CyclicBarrier,以帮助用户理解不同工具的应用场景。 另外,用户可能对Semaphore的实际应用例子感兴趣,比如如何用Semaphore实现一个资源池,或者限制同时执行的线程数量。给出代码示例会更有帮助,但要注意代码的正确性和简洁性,避免让用户感到困惑。 还需要提到Semaphore的公平性问题,即是否支持公平锁,以及在使用时需要注意的事项,比如避免死锁,正确释放许可证等。这些细节能帮助用户避免常见的陷阱,正确使用Semaphore。 最后,总结Semaphore在并发编程中的重要性,强调其在资源管理和流量控制中的作用,让用户明白为什么需要掌握这个工具。同时,结合用户之前的问题,可能他们正在系统学习Java并发包中的各个组件,所以保持回答的结构清晰,层次分明,有助于用户逐步构建知识体系。</think>--- **Semaphore(信号量)** 是 Java 并发编程中用于**控制多线程对共享资源访问权限**的同步工具,其核心思想是**通过“许可证”机制限制并发线程的数量**。以下是详细说明: --- ### **1. 核心功能** - **资源访问控制**: Semaphore 维护一组“许可证”(permits),线程必须获取许可证才能访问资源,访问结束后释放许可证。 - 若许可证被耗尽,新线程需**阻塞等待**,直到其他线程释放许可证。 - 类似现实中的“停车场车位管理”:车位总数固定,车辆进出需占用/释放车位。 - **典型应用场景**: - 数据库连接池(限制同时使用的连接数) - 限流(如接口每秒最多处理 100 个请求) - 多线程任务调度(控制并行任务数) --- ### **2. 核心方法** | 方法 | 说明 | | --- | --- | | `Semaphore(int permits)` | 创建非公平信号量,指定许可证总数 | | `Semaphore(int permits, boolean fair)` | 指定许可证总数及是否公平模式 | | `acquire()` | 获取 1 个许可证(阻塞直到成功) | | `acquire(int n)` | 获取 `n` 个许可证 | | `release()` | 释放 1 个许可证 | | `release(int n)` | 释放 `n` 个许可证 | | `tryAcquire()` | 尝试获取许可证(立即返回成功/失败) | | `availablePermits()` | 返回当前可用许可证数量 | --- ### **3. 代码示例** ```java // 创建一个允许 3 个线程同时访问的信号量 Semaphore semaphore = new Semaphore(3); Runnable task = () -> { try { semaphore.acquire(); // 获取许可证 System.out.println(Thread.currentThread().getName() + " 占用资源"); Thread.sleep(2000); // 模拟资源占用 } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); // 必须释放许可证 System.out.println(Thread.currentThread().getName() + " 释放资源"); } }; // 启动 5 个线程,但只有 3 个能同时运行 for (int i = 0; i < 5; i++) { new Thread(task).start(); } ``` **输出结果**: ``` Thread-0 占用资源 Thread-1 占用资源 Thread-2 占用资源 (2 秒后) Thread-0 释放资源 Thread-1 释放资源 Thread-2 释放资源 Thread-3 占用资源 Thread-4 占用资源 ... ``` --- ### **4. 关键特性** - **公平性**: - 默认非公平模式(竞争许可证时可能“插队”)。 - 设置 `fair=true` 时,按线程等待顺序分配许可证(类似公平锁)。 - **动态调整许可证**: - 可通过 `release()` 增加许可证(超出初始值),但需谨慎使用。 - **与锁的区别**: - Semaphore 不绑定具体资源,而是通过许可证控制访问线程数。 - 锁(如 `ReentrantLock`)通常用于互斥访问,一次只允许一个线程。 --- ### **5. 注意事项** - **避免死锁**:确保 `acquire()` 后必有 `release()`(即使发生异常)。 - **资源泄漏**:未释放许可证可能导致后续线程永久阻塞。 - **许可证数量合理性**:初始值需根据系统负载和资源容量设定。 --- ### **总结** Semaphore 是 Java 并发包中**解决资源竞争和流量控制的核心工具**,通过灵活的许可证机制,既能保证系统稳定性,又能充分利用硬件资源。理解其原理和用法是掌握高并发编程的重要基础。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值