FreeRTOS信号量
前面介绍过,队列(queue)可以用于传输数据:在任务之间,任务和中断之间。
消息队列用于传输多个数据,但是有时候我们只需要传递一个状态,这个状态值需要用一个数值表示,比如:
卖家:做好了1个包子,做好了2个包子,做好了3个包子!
买家:买了一个包子,包子数量减1
这个停车位我占了,停车位减1
我开车走了,停车位加1
在这些情况下,我们只需要维护一个数值,使用信号量效率更高,更节省内存。
FreeRTOS信号量简介
信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。其中,“同步”指的是任务之间的同步,即信号量可以使得一个任务等待另一个任务完成某件事后,才继续执行;而“有序访问”指的是对被多任务或中断访问的共享资源(如全局变量)的管理,当一个任务在访问(读取或写入)一个共享资源时,信号量可以防止其他任务或中断在这期间访问(读取或写入)这个共享资源。

FreeRTOS二值信号量
前面说过,信号量是基于队列实现的,二值信号量也不例外,二值信号量实际上就是一个队列长度为1的队列,在这种情况下,队列就只有空和满两种情况,这就是二值信号量,二值信号量通常用于互斥访问或任务同步,与互斥信号量类似,但是二值信号量有优先级反转的问题:优先级反转就是指,当一个高优先级任务因获取一个低优先级任务获取而处于没有资源状态的二值信号量时,这个高优先级的任务就将被阻塞,直到低优先级任务释放二值信号量,在此之前,如果有一个优先级介于高优先级和低优先级之间的中等优先级任务就绪,那么这个中等优先级任务就会抢占低优先级任务,那么,这三个任务中,高优先级任务反而要最后执行,这就是二值信号量带来的优先级反转问题。
FreeRTOS计数型信号量
计数型信号量和二值信号量类似,二值信号量相当于队列长度为1 的队列,因此二值信号量只能容纳一个资源,这也是为什么命名为二值信号量,而计数型信号量相当于队列长度大于0的队列,因此计数型信号零能容纳多个资源,这是在计数型信号量被创建的时候确定的。
计数型信号量适用于下面两种场合:
事件计数
在这种场合下,每次事件发生后,在事件处理函数中释放计数型信号量(计数型信号量的资源数加1),其他等待事件发生的任务 获取计数型信号量(计数型信号量的资源数减1),这么以来等待事件发生的任务就可以在成功获取到计数型信号量之后执行相应的操作,在这种场合下,计数型信号量的资源数一般在创建时设置为0。
资源管理
在这种场合下,计数型信号量的资源数代表着共享资源的可用数量,例如前面举例中的停车场中的空车位。一个任务想要访问共享资源,就必须先获取这个共享资源的计数型信号量,之后在成功获取了计数型信号量之后,才可以对这个共享资源进行操作,当然,在使用完共享资源之后也要释放这个共享资源的计数型信号量。在这种场合下,计数型信号量的资源数一般在创建时设置为受其管理的共享资源的最大可用数量。
信号量的特性
信号量的常规操作
信号量这个名字起的很恰当:
信号:起通知作用
量:还可以表示资源的数量
当“量”没有限制时,它就是“计数型信号量”(Counting Semaphores)
当“量”只有0、1两个取值时,它就是“二值信号量”(Binary Seamphores)
支持的动作:“give”给出资源,计数值加1,“take”获得资源,计数值减1
计数信号量的典型场景是:
事件计数:事件产生时“give"信号量,让计数值加1;处理事件时要先”take“信号量,也就是获得信号量,让计数值减1
资源管理:要想访问资源需要先”take“信号量,让计数值减1,用完资源后”give“信号量,让计数值加1
信号量的”give“、”take“双方并不需要相同,可以用于生产者-消费者场合;
生产者为任务A,B,消费者为任务C,D
一开始信号量的计数值为0,如果任务C,D想获得信号量,会有两种结果:
阻塞:买不到东西咱就等等吧,可以定个闹钟(超时时间)
即可返回失败:不等
任务A,B可以生产资源,就是让信号量的计数值增加1,并且把等待这个资源的顾客唤醒
唤醒谁?谁优先级高就唤醒谁,如果大家优先级都一样,就唤醒等待时间最长的人
二值信号量和计数型信号量的唯一差别:就是计数值的最大值被限定为1

信号量跟队列的对比
队列 | 信号量 |
可以容纳多个数据,创建队列时有2部分内存:队列结构体、存储数据的空间 | 只有计数值,无法容纳其他数据 创建信号量时,只需要分配信号量结构体 |
生产者:没有空间存入数据时可以阻塞 | 生产者:用于不阻塞,计数值已经达到最大值时返回失败 |
消费者:没有数据时可以阻塞 | 消费者:没有资源时可以阻塞 |
两种信号量对比
二进制信号量 | 计数型信号量 |
被创建时初始值为0 | 被创建时初始值可以设定 |
其他操作是一样的 | 其他操作是一样的 |
二值信号量
二值信号量的本质是一个队列长度为1的队列,该队列就只有空和满两种情况,这就是二值。
二值信号量通常用于互斥访问或任务同步,与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题,所以二值信号量更适合用于同步。

二值信号量相关API函数
使用二值信号量的过程:创建二值信号量->释放二值信号量->获取二值信号量
使用信号量时,先创建,然后去添加资源、获得资源,使用句柄来表示一个信号量
函数 | 描述 |
xSemaphoreCreateBinary() | 使用动态方式创建二值信号量 |
xSemaphoreCreateBinaryStatic() | 使用静态方式创建二值信号量 |
xSemaphoreGive() | 释放二值信号量 |
xSemaphoreGiveFromISR() | 在中断中释放信号量 |
xSemaphoreTake() | 获取信号量 |
xSemaphoreTakeFromISR() | 在中断中获取信号量 |
这些函数其实都可以在semphr.h头文件中找到,它们都是一些宏定义,本质上用的其实都是Queue的函数
创建二值信号量
/*
创建一个二进制信号量,返回它的句柄
此函数内部会分配信号量结构体
返回值:返回句柄,非NULL表示成功可以看出,动态创建二值信号量实际上是调用了函数xQueueGenericCreate()
创建了一个队列长度为1且队列项目大小为信号量队列项目大小的二值信号量类型队列
*/
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )/*
创建一个二进制信号量,返回它的句柄
此函数无需动态分配内存,所以需要现有一个StaticSemaphore_t结构体,并传入它的指针
返回值:返回句柄,非NULL表示成功从 上 面 的 代 码 中 可 以 看 出 , 函 数 xSemaphoreCreateStatic() 实 际 上 是 调 用 了 函 数
xQueueGenericCreateStatic()创建了一个队列长度为 1 且队列项目大小为信号量队列项目大小的
二值信号量类型队列,需要用户手动分配提供创建二值信号量的内存
*/
#define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
获取信号量
/*
此函数用于获取信号量,如果信号量处于没有资源的状态,那么此函数可以选择将任务进
行阻塞,如果成功获取了信号量,那信号量的资源数将会减 1。该函数实际上是一个宏定义
*/
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,TickType_t xTicksToWait )
{BaseType_t xEntryTimeSet = pdFALSE;TimeOut_t xTimeOut;Queue_t * const pxQueue = xQueue;#if ( configUSE_MUTEXES == 1 )BaseType_t xInheritanceOccurred = pdFALSE;#endif/* Check the queue pointer is not NULL. */configASSERT( ( pxQueue ) );/* 信号量类型队列的项目大小为0 */configASSERT( pxQueue->uxItemSize == 0 );/* Cannot block if the scheduler is suspended. */#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ){configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );}#endif/*lint -save -e904 This function relaxes the coding standard somewhat to allow return* statements within the function itself. This is done in the interest* of execution time efficiency. */for( ; ; ){ /*进入临界区*/taskENTER_CRITICAL();{/* 获取信号量的资源数 */const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;/* 判断信号量是否有资源 */if( uxSemaphoreCount > ( UBaseType_t ) 0 ){traceQUEUE_RECEIVE( pxQueue );/* 更新信号量的资源数 */pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;#if ( configUSE_MUTEXES == 1 ){if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ){/* 设置互斥信号量的持有者并更新互斥信号量的持有次数 */pxQueue->u.xSemaphore.xMutexHolder = pvTaskIncrementMutexHeldCount();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* configUSE_MUTEXES *//* 判断信号量的获取阻塞任务列表中是否有任务 */if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ){/*将阻塞任务从信号量获取阻塞任务列表中移除*/if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ){/*根据需要进行任务切换*/queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}taskEXIT_CRITICAL();return pdPASS;}/*信号量没有资源*/else{/*判断是否不选择阻塞等待信号量*/if( xTicksToWait == ( TickType_t ) 0 ){/* 此宏用于启用互斥信号量 */#if ( configUSE_MUTEXES == 1 ){configASSERT( xInheritanceOccurred == pdFALSE );}#endif /* configUSE_MUTEXES *//* 退出临界区*/taskEXIT_CRITICAL();traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;}/*选择阻塞等待信号量*/else if( xEntryTimeSet == pdFALSE ){/* 队列满,任务需要阻塞记录此时系统节拍计数器 值和溢出次数用于下面对阻塞时间进行补偿*/vTaskInternalSetTimeOutState( &xTimeOut );xEntryTimeSet = pdTRUE;}else{/* Entry time was already set. */mtCOVERAGE_TEST_MARKER();}}}taskEXIT_CRITICAL();/* 挂起任务调度器 */vTaskSuspendAll();/*信号量队列上锁*/prvLockQueue( pxQueue );/* 判断阻塞时间补偿后,是否还需要阻塞 */if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ){/* 判断队列是否为空 */if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );#if ( configUSE_MUTEXES == 1 ){if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ){taskENTER_CRITICAL();{/*进行优先级继承,这是互斥信号量用于解决优先级翻转问题的*/xInheritanceOccurred = xTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder );}taskEXIT_CRITICAL();}else{mtCOVERAGE_TEST_MARKER();}}#endif /* if ( configUSE_MUTEXES == 1 ) *//*将任务添加到队列写入阻塞任务列表中进行阻塞*/vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );prvUnlockQueue( pxQueue );/*恢复任务调度器*/if( xTaskResumeAll() == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}/*队列不为空*/else{/* There was no timeout and the semaphore count was not 0, so* attempt to take the semaphore again. */prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();}}else{/* Timed out. */prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();/* If the semaphore count is 0 exit now as the timeout has* expired. Otherwise return to attempt to take the semaphore that is* known to be available. As semaphores are implemented by queues the* queue being empty is equivalent to the semaphore count being 0. */if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){#if ( configUSE_MUTEXES == 1 ){/* xInheritanceOccurred could only have be set if* pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to* test the mutex type again to check it is actually a mutex. */if( xInheritanceOccurred != pdFALSE ){taskENTER_CRITICAL();{UBaseType_t uxHighestWaitingPriority;/* This task blocking on the mutex caused another* task to inherit this task's priority. Now this task* has timed out the priority should be disinherited* again, but only as low as the next highest priority* task that is waiting for the same mutex. */uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority );}taskEXIT_CRITICAL();}}#endif /* configUSE_MUTEXES */traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;}else{mtCOVERAGE_TEST_MARKER();}}} /*lint -restore */
}
释放信号量
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
这里其实和上面的获取是类似的,碍于篇幅有限,不给出源码。
在任务中使用 | 在ISR中使用 | |
give | xSemaphoreGive | xSemaphoreGiveFromISR |
take | xSemaphoreTake | xSemaphoreTakeFromISR |
删除
对于动态创建的信号量,不再需要使用它们时,可以删除它们以回收内存
vSemaphoreDelete可以删除二值信号量,计数型信号量,函数原型如下:
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
计数型信号量
计数型信号量相当于队列长度大于1的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定。
计数型信号量相关API函数
函数 | 描述 |
xSemaphoreCreateCounting() | 使用动态方法创建计数型信号量 |
xSemaphoreCreateCountingStatic() | 使用静态方法创建计数型信号量 |
uxSemaphoreGetCount() | 获取信号量的计数值 |
计数值信号量的获取和释放和二值信号量的相同,这里不再赘述。
计数型信号量创建
/*
uxMaxCount:计数值的最大值限定
uxInitialCount:计数值的初始值
NULL:创建失败
其他值:创建成功返回计数型信号量的句柄
*/
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
获取信号量当前计数值大小
/*
xSemaphore:信号量句柄
返回值:整数,当前信号量的计数值大小
*/
#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
个人总结
信号量是一种特殊的队列,其中二值信号量是长度为1的队列,计数型信号量是长度大于1的队列
使用信号量,只是传递一个状态,而不是像队列一样可以缓存数据,然后进行数据交流,信号量相比于队列更加轻量化,只需要创建信号量结构体,队列不仅需要申请创建队列的结构体还包括存储数据的缓存区。
二值信号量其实是一种特殊的计数型信号量,只有0和1两个计数值,常常用于互斥访问和任务间同步,但是二值信号量会导致优先级翻转的问题,互斥量被引申出解决该问题,所以二值信号量最合适用于任务同步。
其实,不管是信号量,队列,互斥量,事件组等IPC(在线程通信)都是这样,都要先创建一个中间结构体,任务之间通过该结构体传输信息,进行交流,这是一种间接的任务之间通信方式。
相关文章:

FreeRTOS信号量
前面介绍过,队列(queue)可以用于传输数据:在任务之间,任务和中断之间。消息队列用于传输多个数据,但是有时候我们只需要传递一个状态,这个状态值需要用一个数值表示,比如:…...

Leetcode.2385 感染二叉树需要的总时间
题目链接 Leetcode.2385 感染二叉树需要的总时间 Rating : 1711 题目描述 给你一棵二叉树的根节点 root,二叉树中节点的值 互不相同 。另给你一个整数 start。在第 0分钟,感染 将会从值为 start的节点开始爆发。 每分钟,如果节点…...

[蓝桥杯 2022 国 B] 卡牌(贪心/二分)
题目传送门 该题第一思路是想去模拟题目中所描述的过程 这里我选择从大到小遍历可能凑出的牌套数,计算凑出它需要补的牌数以及判断是否会超出能补的牌数 #include<iostream> #include<climits> #include<vector> #include<algorithm> #def…...

1301:大盗阿福
经典的dp打家劫舍问题状态设计dp[i][0]:在前i个店铺中选,且不选第i家的最大和dp[i][1]:在前i个店铺中选,且选第i家的最大和状态转移dp[i][0] max(dp[i-1][1], dp[i-1][0];第i家店不选,那么我们可以选第i-1个店 也可以…...

Netty——序列化的作用及自定义协议
序列化的作用及自定义协议序列化的重要性大小对比效率对比自定义协议序列化数据结构自定义编码器自定义解码器安全性验证NettyClientNettyServerNettyClientTestHandlerNettyServerTestHandler结果上一章已经说了怎么解决沾包和拆包的问题,但是这样离一个成熟的通信…...
一起Talk Android吧(第五百零五回:如何调整组件在约束布局中的大小)
文章目录 背景介绍调整方法各位看官们大家好,上一回中咱们说的例子是"如何调整组件在约束布局中的位置",这一回中咱们说的例子是" 如何调整组件在约束布局中的大小"。闲话休提,言归正转, 让我们一起Talk Android吧! 背景介绍 在使用约束(constraintl…...

【数据库】数据库的完整性
第五章 数据库完整性 数据库完整性 数据库的完整性是指数据的正确性和相容性 数据的正确性是指数据是符合现实世界语义,反映当前实际状况的数据的相容性是指数据库的同一对象在不同的关系中的数据是符合逻辑的 关系模型中有三类完整性约束:实体完整性…...

基因净化车间装修设计方案SICOLAB
基因净化车间的设计方案应该根据实际需求进行定制,以下是一些规划建设要点和洁净设计要注意的事项:一、净化车间规划建设要点:(1)基因车间的面积应该根据实验项目的规模进行规划,包括充足的操作区域和足够的…...

java 内部类的四种“写法”
基本介绍语法格式分类成员内部类静态内部类局部内部类匿名内部类(🐂🖊)一、基本介绍 : 1.概述当一个类的内部又完整地嵌套了另一个类时,被嵌套于内部的“内核”我们称之为“内部类”(inner class);而包含该…...

【python】main方法教程
嗨害大家好鸭! 我是小熊猫~ 首先 if name "main": 可以看成是python程序的入口, 就像java中的main()方法, 但不完全正确。 事实上python程序是从上而下逐行运行的, 在.py文件中, 除…...

公司对不同职级能力抽象要求的具体化
要先把当前级别要求的能力提升到精通,然后尝试做下一级别的事情。 但可能不确定高一级的能力要求究竟怎样,不同Title,如“工程师”“高级工程师”和“资深工程师”等。但这样 Title 对我们理解不同级别的能力要求,完全无用。“高…...
Java之MinIO存储桶和对象API使用
环境搭建 创建一个 maven项目,引入依赖: <!-- minio依赖--><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.3.3</version></dependency><!-- 官方 minio…...
如何用java实现同时进行多个请求,可以将它们并行执行,从而减少总共的请求时间。
1.使用线程池 通过使用Java提供的线程池,可以将多个请求分配到不同的线程中并行执行。可以通过创建固定数量的线程池,然后将请求分配给线程池来实现。线程池会自动管理线程的数量和复用,从而减少了线程创建和销毁的开销,提高了程序…...

高端装备的AC主轴头结构
加工机器人的AC主轴头和位置相关动力学特性1. 位置依赖动态特性及其复杂性2. AC主轴头2.1 常见主轴头摆角结构2.2 摆动机构3. 加装AC主轴头的作用和局限性4. 切削机器人的减速器类型5. 其他并联结构形式参考文献资料1. 位置依赖动态特性及其复杂性 However, FRF measurements …...

【Proteus仿真】【51单片机】粮仓温湿度控制系统设计
文章目录一、功能简介二、软件设计三、实验现象联系作者一、功能简介 本项目使用Proteus8仿真51单片机控制器,使用声光报警模块、LCD1602显示模块、DHT11温湿度模块、继电器模块、加热加湿除湿风扇等。 主要功能: 系统运行后,LCD1602显示传…...

【LINUX】环境变量以及main函数的参数
文章目录前言环境变量常见环境变量:设置环境变量:和环境变量相关的命令:环境变量的组织方式:获取环境变量环境变量可以被子进程继承环境变量总结main函数的参数前言 大家好久不见,今天分享的内容是环境变量和main函数…...

使用Pyparsing为嵌入式开发定义自己的脚本语言
Python在嵌入式开发中也很流行生成实用脚本。Pyparsing还允许你轻松地定义在Python上下文中运行的定制脚本语言。Python实现的系统旨在能够独立执行用户传递的一系列命令。你希望系统以脚本的形式接收命令。用户应该能够定义条件。这种对通信中逻辑元素的最初简单的声音要求&am…...
C win32基础学习(二)
上一篇我们已经介绍了关于窗口程序的一些基本知识。从本篇开始我们将正式进入C win32的学习中去。 正文 窗口创建过程 定义WinMain函数 定义窗口处理函数(自定义,处理消息) 注册窗口类(向操作系统写入一些数据) 创建窗口(内存…...
理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
关于SOLID原则,我们已经学过单一职责、开闭、里式替换、接口隔离这四个原则。今天,我们再来学习最后一个原则:依赖反转原则。在前面几节课中,我们讲到,单一职责原则和开闭原则的原理比较简单,但是,想要在实践中用好却比较难。而今天我们要讲到的依赖反转原则正好相反。这个原则…...

读书笔记//《数据分析之道》
出版时间:2022年 作者曾在互联网大厂做数据分析。从举例可以洞见作者的工作经历。 点评:作者在数据分析领域非常资深,尝试在书中提供一个数据分析工作框架参考。书本内容有点感觉是ppt的集合,辅以案例说明。不过,干货还…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...