FreeRTOS 13:FreeRTOS队列的读原理

队列读取消息

FreeRTOS 中用于从队列中读取消息的 API 函数如下表所示:

xQueueReceive

BaseType_t xQueueReceive( QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait )
{BaseType_t xEntryTimeSet = pdFALSE;TimeOut_t xTimeOut;Queue_t * const pxQueue = xQueue;/* 检查指针是否不为空。 */configASSERT( ( pxQueue ) );/* 如果数据大小不为零,则接收数据的缓冲区不能为 NULL。 */configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );/* 如果调度器被挂起,则不能阻塞。 */#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ){configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );}#endif/* lint -save -e904  此函数放宽了编码标准,允许在函数内部使用 return 语句。这是为了提高执行效率。 */for( ; ; ){taskENTER_CRITICAL();{const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;/* 队列中是否有数据?调用任务必须是希望访问队列的最高优先级任务。 */if( uxMessagesWaiting > ( UBaseType_t ) 0 ){/* 有数据可用,移除一个项目。 */prvCopyDataFromQueue( pxQueue, pvBuffer );traceQUEUE_RECEIVE( pxQueue );pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;/* 现在队列中有空闲空间,是否有任务在等待向队列发送数据?如果有,解除最高优先级等待任务的阻塞。 */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 ){/* 队列为空且未指定阻塞时间(或阻塞时间已过期),因此离开。 */taskEXIT_CRITICAL();traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;}else if( xEntryTimeSet == pdFALSE ){/* 队列为空且指定了阻塞时间,因此配置超时结构。 */vTaskInternalSetTimeOutState( &xTimeOut );xEntryTimeSet = pdTRUE;}else{/* 入口时间已设置。 */mtCOVERAGE_TEST_MARKER();}}}taskEXIT_CRITICAL();/* 退出临界区后,中断和其他任务可以向队列发送和接收数据。 */vTaskSuspendAll();prvLockQueue( pxQueue );/* 更新超时状态以查看是否已过期。 */if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ){/* 超时未过期。如果队列仍然为空,将任务放入等待接收队列的任务列表中。 */if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );prvUnlockQueue( pxQueue );if( xTaskResumeAll() == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}else{/* 队列中再次有数据。循环回去尝试读取数据。 */prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();}}else{/* 超时。如果队列中没有数据则退出,否则循环回去尝试读取数据。 */prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;}else{mtCOVERAGE_TEST_MARKER();}}} /* lint -restore */
}

xQueueReceive 函数用于从队列中接收数据。

  1. 参数检查

    • 检查队列指针 xQueue 是否为空。

    • 检查缓冲区指针 pvBuffer 是否为空,且队列项大小不为零。

    • 检查调度器是否被挂起,如果是且阻塞时间不为零,则断言失败。

  2. 临界区操作

    • 进入临界区,检查队列中是否有数据。

  3. 数据接收

    • 如果队列中有数据,调用 prvCopyDataFromQueue 复制数据到缓冲区。

    • 更新队列中等待的消息数量。

    • 检查是否有任务在等待向队列发送数据,如果有,解除最高优先级任务的阻塞。

    • 退出临界区,返回成功。

  4. 超时处理

    • 如果队列为空且阻塞时间为0,退出临界区,记录失败,返回队列为空。

    • 如果队列为空且阻塞时间不为0,配置超时结构,设置入口时间。

  5. 任务调度

    • 挂起所有任务,锁定队列。

    • 检查超时状态,如果超时未过期且队列为空,将任务放入等待接收队列的任务列表中。

    • 如果超时未过期且队列中有数据,解锁队列,循环回去尝试读取数据。

    • 如果超时已过期且队列为空,解锁队列,恢复所有任务,记录失败,返回队列为空。

    • 如果超时已过期且队列中有数据,解锁队列,恢复所有任务,循环回去尝试读取数据。

xQueuePeek

BaseType_t xQueuePeek( QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait )
{BaseType_t xEntryTimeSet = pdFALSE;TimeOut_t xTimeOut;int8_t * pcOriginalReadPosition;Queue_t * const pxQueue = xQueue;/* 检查指针是否不为空。 */configASSERT( ( pxQueue ) );/* 接收数据的缓冲区只有在数据大小为零时才可以为空(即没有数据复制到缓冲区)。 */configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );/* 如果调度器被挂起,则不能阻塞。 */#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ){configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );}#endif/*lint -save -e904  此函数放宽了编码标准,允许在函数内部使用return语句。这是为了提高执行效率。 */for( ; ; ){taskENTER_CRITICAL();{const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;/* 队列中现在有数据吗?调用任务必须是最高优先级的任务才能访问队列。 */if( uxMessagesWaiting > ( UBaseType_t ) 0 ){/* 记录读取位置,以便在从队列中读取数据后重置,因为此函数只是预览数据,而不是移除它。 */pcOriginalReadPosition = pxQueue->u.xQueue.pcReadFrom;prvCopyDataFromQueue( pxQueue, pvBuffer );traceQUEUE_PEEK( pxQueue );/* 数据不会被移除,因此重置读取指针。 */pxQueue->u.xQueue.pcReadFrom = pcOriginalReadPosition;/* 数据将留在队列中,因此检查是否有其他任务在等待这些数据。 */if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ){if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ){/* 等待的任务优先级高于当前任务。 */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}taskEXIT_CRITICAL();return pdPASS;}else{if( xTicksToWait == ( TickType_t ) 0 ){/* 队列为空且未指定阻塞时间(或阻塞时间已过期),因此现在离开。 */taskEXIT_CRITICAL();traceQUEUE_PEEK_FAILED( pxQueue );return errQUEUE_EMPTY;}else if( xEntryTimeSet == pdFALSE ){/* 队列为空且指定了阻塞时间,因此配置超时结构以准备进入阻塞状态。 */vTaskInternalSetTimeOutState( &xTimeOut );xEntryTimeSet = pdTRUE;}else{/* 入口时间已设置。 */mtCOVERAGE_TEST_MARKER();}}}taskEXIT_CRITICAL();/* 退出临界区后,中断和其他任务可以发送和接收队列中的数据。 */vTaskSuspendAll();prvLockQueue( pxQueue );/* 更新超时状态以查看是否已过期。 */if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ){/* 超时未过期,检查队列中现在是否有数据,如果没有则进入阻塞状态等待数据。 */if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){traceBLOCKING_ON_QUEUE_PEEK( pxQueue );vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );prvUnlockQueue( pxQueue );if( xTaskResumeAll() == pdFALSE ){portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}else{/* 队列中现在有数据,因此不要进入阻塞状态,而是返回以尝试获取数据。 */prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();}}else{/* 超时已过期。如果队列中仍然没有数据,则退出,否则返回并再次尝试读取数据。 */prvUnlockQueue( pxQueue );( void ) xTaskResumeAll();if( prvIsQueueEmpty( pxQueue ) != pdFALSE ){traceQUEUE_PEEK_FAILED( pxQueue );return errQUEUE_EMPTY;}else{mtCOVERAGE_TEST_MARKER();}}} /*lint -restore */
}

xQueuePeek 函数用于从队列中预览数据而不移除数据。

  1. 参数检查:确保队列指针和缓冲区指针有效。

  2. 调度器状态检查:确保在调度器挂起时不会阻塞。

  3. 临界区操作:进入临界区,检查队列中是否有数据。

  4. 数据预览:如果有数据,记录当前读取位置,复制数据到缓冲区,然后重置读取指针。

  5. 任务唤醒:如果有任务在等待队列中的数据,唤醒这些任务。

  6. 阻塞等待:如果队列为空且设置了阻塞时间,进入阻塞状态等待数据。

  7. 超时处理:如果超时,返回错误码 errQUEUE_EMPTY。如果队列中有数据,返回成功码 pdPASS

xQueueReceiveFromISR

/*** queue.h* <pre>* BaseType_t xQueueReceiveFromISR(*                                     QueueHandle_t    xQueue,*                                     void             *pvBuffer,*                                     BaseType_t       *pxTaskWoken*                                 );* </pre>** 从队列接收一个项目。从中断服务例程 (ISR) 中调用此函数是安全的。** @param xQueue 要从中接收项目的队列句柄。** @param pvBuffer 指向缓冲区的指针,接收到的项目将被复制到该缓冲区。** @param pxTaskWoken 可能有任务因队列空间不足而被阻塞。如果 xQueueReceiveFromISR 导致这样的任务解除阻塞,* *pxTaskWoken 将被设置为 pdTRUE,否则 *pxTaskWoken 将保持不变。** @return 如果成功从队列接收项目,则返回 pdTRUE,否则返回 pdFALSE。** 使用示例:* <pre>** QueueHandle_t xQueue;** // 创建队列并发布一些值的函数。* void vAFunction( void *pvParameters )* {* char cValueToPost;* const TickType_t xTicksToWait = ( TickType_t )0xff;**  // 创建一个能够容纳 10 个字符的队列。*  xQueue = xQueueCreate( 10, sizeof( char ) );*  if( xQueue == 0 )*  {*      // 创建队列失败。*  }**  // ...**  // 在 ISR 中使用的字符。如果队列已满,此任务将等待 xTicksToWait 个滴答。*  cValueToPost = 'a';*  xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );*  cValueToPost = 'b';*  xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );**  // ... 继续发布字符 ... 当队列满时,此任务可能会阻塞。**  cValueToPost = 'c';*  xQueueSend( xQueue, ( void * ) &cValueToPost, xTicksToWait );* }** // 输出在队列中接收到的所有字符的 ISR。* void vISR_Routine( void )* {* BaseType_t xTaskWokenByReceive = pdFALSE;* char cRxedChar;**  while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )*  {*      // 接收到一个字符。立即输出该字符。*      vOutputCharacter( cRxedChar );**      // 如果从队列中移除字符导致发布到队列的任务解除阻塞,cTaskWokenByReceive 将被设置为 pdTRUE。*      // 无论此循环迭代多少次,只有一个任务会被唤醒。*  }**  if( xTaskWokenByReceive != pdFALSE )*  {*      taskYIELD ();*  }* }* </pre>* \defgroup xQueueReceiveFromISR xQueueReceiveFromISR* \ingroup QueueManagement*/
BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,void * const pvBuffer,BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;

BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,void * const pvBuffer,BaseType_t * const pxHigherPriorityTaskWoken )
{BaseType_t xReturn;UBaseType_t uxSavedInterruptStatus;Queue_t * const pxQueue = xQueue;// 检查队列指针是否有效configASSERT( pxQueue );// 检查缓冲区指针是否有效,除非队列中的数据大小为0configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );// 检查中断优先级是否有效portASSERT_IF_INTERRUPT_PRIORITY_INVALID();// 保存当前中断状态并屏蔽中断uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();{const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;// 检查队列中是否有数据if( uxMessagesWaiting > ( UBaseType_t ) 0 ){const int8_t cRxLock = pxQueue->cRxLock;// 记录从中断服务例程接收数据的事件traceQUEUE_RECEIVE_FROM_ISR( pxQueue );// 从队列中复制数据到缓冲区prvCopyDataFromQueue( pxQueue, pvBuffer );// 更新队列中剩余的消息数量pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;// 如果队列未被锁定if( cRxLock == queueUNLOCKED ){// 检查是否有任务在等待发送数据if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ){// 尝试从事件列表中移除等待任务if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ){// 如果等待的任务优先级高于当前任务,强制上下文切换if( pxHigherPriorityTaskWoken != NULL ){*pxHigherPriorityTaskWoken = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{// 如果队列被锁定,更新锁计数configASSERT( cRxLock != queueINT8_MAX );pxQueue->cRxLock = ( int8_t ) ( cRxLock + 1 );}// 返回成功xReturn = pdPASS;}else{// 队列为空,返回失败xReturn = pdFAIL;traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );}}// 恢复中断状态portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );return xReturn;
}

xQueueReceiveFromISR 函数用于从中断服务例程(ISR)中接收队列中的数据。具体功能如下:

  1. 参数检查

    • 检查队列指针 xQueue 是否有效。

    • 检查缓冲区指针 pvBuffer 是否有效,除非队列中的数据大小为0。

    • 检查队列中的数据大小是否不为0,因为不能窥探信号量。

  2. 中断优先级检查

    • 确保调用该函数的中断优先级不超过最大系统调用优先级。

  3. 中断屏蔽

    • 保存当前中断状态并屏蔽中断,防止其他中断干扰。

  4. 检查队列状态

    • 检查队列中是否有数据。

  5. 数据窥探

    • 如果队列中有数据,记录当前读取位置,以便稍后恢复。

    • 从队列中复制数据到缓冲区。

    • 恢复读取位置,因为没有实际从队列中移除数据。

  6. 返回结果

    • 如果成功,返回 pdPASS

    • 如果队列为空,返回 pdFAIL,并记录失败事件。

  7. 恢复中断状态

    • 恢复中断状态。

xQueuePeekFromISR

BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue,void * const pvBuffer )
{BaseType_t xReturn;UBaseType_t uxSavedInterruptStatus;int8_t * pcOriginalReadPosition;Queue_t * const pxQueue = xQueue;// 检查队列指针是否有效configASSERT( pxQueue );// 检查缓冲区指针是否有效,除非队列中的数据大小为0configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );// 检查队列中的数据大小是否不为0,因为不能窥探信号量configASSERT( pxQueue->uxItemSize != 0 );// 检查中断优先级是否有效portASSERT_IF_INTERRUPT_PRIORITY_INVALID();// 保存当前中断状态并屏蔽中断uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();{// 检查队列中是否有数据if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 ){// 记录从中断服务例程窥探数据的事件traceQUEUE_PEEK_FROM_ISR( pxQueue );// 记录当前读取位置,以便稍后恢复pcOriginalReadPosition = pxQueue->u.xQueue.pcReadFrom;// 从队列中复制数据到缓冲区prvCopyDataFromQueue( pxQueue, pvBuffer );// 恢复读取位置,因为没有实际从队列中移除数据pxQueue->u.xQueue.pcReadFrom = pcOriginalReadPosition;// 返回成功xReturn = pdPASS;}else{// 队列为空,返回失败xReturn = pdFAIL;// 记录从中断服务例程窥探数据失败的事件traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue );}}// 恢复中断状态portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );return xReturn;
}

从中断服务例程(ISR)中窥探队列的功能

  1. 开始:函数开始执行。

  2. 队列指针有效?:检查队列指针是否有效。

  3. 缓冲区指针有效?:检查缓冲区指针是否有效。

  4. 队列数据大小不为0?:检查队列中的数据大小是否不为0。

  5. 保存中断状态并屏蔽中断:保存当前中断状态并屏蔽中断。

  6. 队列中有数据?:检查队列中是否有数据。

  7. 记录窥探失败事件:记录从中断服务例程窥探数据失败的事件。

  8. 恢复中断状态:恢复中断状态。

  9. 返回失败:返回失败状态。

  10. 记录窥探事件:记录从中断服务例程窥探数据的事件。

  11. 复制数据到缓冲区:从队列中复制数据到缓冲区。

  12. 恢复读取位置:恢复读取位置。

  13. 返回成功:返回成功状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/7823.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

山东路远生态科技有限公司竣工投产仪式暨产品发布会圆满举行

第二十届三中全会于2024年7月15日至18日在北京举行。全会审议通过了《关于进一步全面深化改革、推进中国式现代化的决定》。其中提到,“要健全因地制宜发展新质生产力体制机制”。 新质生产力是由技术革命性突破、生产要素创新性配置、产业深度转型升级而催生的当代先进生产力…

Vue + Vant Picker实现省市区三级联动

一、picker选择器的数据由columns属性控制&#xff0c;columns中有几个元素就代表该选择器有多少级&#xff0c;通过change方法来给对应列赋值 this.columns [{values: citys,className: "column1",defaultIndex: 0,flex: 1, //控制每列的宽度},{values: citys[0].…

[java][高级]FilterListenerAjax

Filter&Listener&Ajax 目标&#xff1a; 能够使用 Filter 完成登陆状态校验功能 能够使用 axios 发送 ajax 请求 熟悉 json 格式&#xff0c;并能使用 Fastjson 完成 java 对象和 json 串的相互转换 1&#xff0c;Filter 1.1 Filter概述 Filter 表示过滤器&#…

如何使用RabbitMQ和Python实现广播消息

使用 RabbitMQ 和 Python 实现广播消息的过程涉及设置一个消息队列和多个消费者&#xff0c;以便接收相同的消息。RabbitMQ 的 “fanout” 交换机允许你将消息广播到所有绑定的队列。以下是如何实现这一过程的详细步骤。 1、问题背景 在将系统从Morbid迁移到RabbitMQ时&#x…

java.lang.IllegalArgumentException: argument type mismatch问题排查汇总

java.lang.IllegalArgumentException: argument type mismatch 错误通常发生在方法调用时&#xff0c;传入的参数类型与方法签名中声明的参数类型不匹配&#xff0c;错误发生在堆栈跟踪中&#xff0c;MyBatis 反射调用方法设置 Bean 属性时。 以下是一些可能的原因和解决方法…

沉浸式学习新体验:3D虚拟展厅如何重塑教育格局!

3D虚拟展厅对于教育行业产生了深远的影响&#xff0c;主要体现在以下几个方面&#xff1a; 一、创新教学方式 3D虚拟展厅利用三维技术构建的虚拟展示空间&#xff0c;为教育行业带来了一种全新的教学方式。传统的教学方式往往局限于书本和课堂&#xff0c;而3D虚拟展厅则能够…

第107篇:国*攻防比赛中一个多层嵌套的java内存马的反混淆解密分析过程

Part1 前言 大家好&#xff0c;我是ABC_123。一年一度的“大型攻防比赛”已经过去2、3个月了&#xff0c;在此期间陆续收到了多名网友发来的内存马样本&#xff0c;ABC_123一直在抽时间进行分析解密工作。现在很多的内存马都进行了加密混淆&#xff0c;而且一个比一个复杂&…

火山引擎云服务docker 安装

安装 Docker 登录云服务器。 执行以下命令&#xff0c;添加 yum 源。 yum update -y yum install epel-release -y yum clean all yum list依次执行以下命令&#xff0c;添加Docker CE镜像源。更多操作请参考Docker CE镜像。 # 安装必要的一些系统工具 sudo yum install -y yu…

基于SpringBoot的“会员制医疗预约服务管理信息系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“会员制医疗预约服务管理信息系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页界面图 医院信息界面图…

从0开始linux(21)——文件(2)文件重定向

欢迎来到博主的专栏&#xff1a;从0开始linux 博主ID&#xff1a;代码小豪 文章目录 设备文件文件缓冲区重新认识文件描述符重定向 设备文件 在前一篇文章博主提到&#xff0c;当一个c/c进程运行时&#xff0c;会默认打开三个文件流&#xff0c;分别是stdin&#xff0c;stdout…

Claude 3.5 新功能 支持对 100 页的PDF 图像、图表和图形进行可视化分析

Claude 3.5 Sonnet发布PDF图像预览新功能&#xff0c;允许用户分析长度不超过100页的PDF中的视觉内容。 此功能使用户能够轻松上传文档并提取信息&#xff0c;特别适用于包含图表、图形和其他视觉元素的研究论文和技术文档。 视觉PDF分析&#xff1a;用户现在可以从包含各种视觉…

【SQL server】数据库远程连接配置

SQL server远程连接配置 1、数据库远程配置1.身份验证2. 建立入站规则3. SQLServer服务的启动 1、数据库远程配置 1.身份验证 所以在安装过程中需要注意涉及到的的身份验证中&#xff0c;要使用混合模式&#xff0c;并设置密码。2. 建立入站规则 在控制面板中的防火墙管理中…

【Vue 全家桶】5、Vuex(更新中)

目录 概念何时使用搭建vuex环境基本使用getter的使用四个map方法的使用vuex模块化命名空间 概念 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。使用 Vuex 可…

首推!AI大模型课程2024年最新版!从零基础到入行大模型算法工程师,看完这一篇就够了,学完来找我内推!

“ 技术学习无非涵盖三个方面&#xff0c;理论&#xff0c;实践和应用**”** 大模型技术爆火至今已经有两年的时间了&#xff0c;而且大模型技术的发展潜力也不言而喻。因此&#xff0c;很多人打算学习大模型&#xff0c;但又不知道该怎么入手&#xff0c;因此今天就来了解一下…

一站式搭建线上线下交友平台/全开源码交付前后端安装说明

功能亮点 灵魂匹配&#xff1a;基于个人喜好和兴趣&#xff0c;为你推荐最合适的交友对象。 真实认证&#xff1a;所有用户都经过严格认证&#xff0c;确保交友环境真实可靠。 隐私保护&#xff1a;强大的隐私设置&#xff0c;让你轻松掌控个人信息和交友动态。 互动便捷&…

基于数组实现的Huffman树和Huffman编码

一、Huffman树简介 1、定义 树的带权路径长度&#xff0c;就是树中所有的叶节点的权值乘上其到根节点的路径长度。 在含有n 个带权叶子结点的二叉树中&#xff0c;其中带权路径长度&#xff08;Weighted Path Length, WPL&#xff09;最小的二叉树称为哈夫曼树&#xff0c; 也…

图说复变函数论重大错误:将无穷多各异平面误为同一面

黄小宁 医学若将前所未知的“新冠”病毒误为已熟知的流感病毒&#xff0c;后果...&#xff1b;数学将前所未知的点集误为已熟知的集就会引出一连串的重大错误。 h定理&#xff1a;点集AB的必要条件是A≌B。 证&#xff1a;&#xff08;1&#xff09;任何图≌自己是几何学最起码…

SDL简介和初次尝试

文章目录 SDL的用途和概念SDL下载 SDL的用途和概念 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台开发库 &#xff0c;使用C语言写成&#xff0c;SDL提供了数种 操作 图像 &#xff0c;声音输入输出的函数&#xff0c;让开发者使用 相识的代码 就能够开发出跨平台的…

WiFi一直获取不到IP地址是怎么回事?

在当今这个信息化时代&#xff0c;WiFi已成为我们日常生活中不可或缺的一部分。无论是家庭、办公室还是公共场所&#xff0c;WiFi都为我们提供了便捷的无线互联网接入。然而&#xff0c;有时我们可能会遇到WiFi连接后无法获取IP地址的问题&#xff0c;这不仅影响了我们的网络使…

【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程

1、定义图像显示函数 首先定义一个函数&#xff0c;函数的作用是通过plt库显示两幅图&#xff0c;为后续实验做准备。该函数的主要功能是&#xff1a; 从指定路径加载图像显示图像的基本信息将图像从BGR格式转换为RGB格式并在一个图形窗口中显示两幅图像进行对比 import nump…