NonBlockingDelay:嵌入式非阻塞延时库原理与实践

news2026/4/4 3:39:51
1. 项目概述NonBlockingDelay 是一个专为嵌入式系统设计的轻量级、零依赖、单头文件.hpp非阻塞延时库。其核心目标是彻底替代delay()这类会挂起 CPU、阻塞所有任务执行的同步延时函数使开发者能够在维持主循环loop()或任务持续运行的前提下精确、可靠地触发定时事件——例如 LED 状态翻转、传感器采样、通信超时检测、状态机迁移等典型嵌入式场景。该库不依赖任何操作系统抽象层如 FreeRTOS 的vTaskDelay、硬件定时器外设驱动如 STM32 HAL 的HAL_Delay或标准 C 库时间函数如clock()或gettimeofday()。它仅需一个单调递增的毫秒级时间源通常由millis()提供通过纯软件逻辑实现状态机式的延时管理。这种设计使其具备极强的可移植性从 Arduino AVRATmega328P、ESP32、nRF52到基于 CMSIS 的 Cortex-M0/M3/M4/M7 MCU乃至裸机 RISC-V 平台只要能提供uint32_t millis()接口即可无缝集成。其本质是一个时间戳比较器Timestamp Comparator每个NonBlockingDelay实例内部维护一个uint32_t m_lastTriggerTime成员记录上一次触发动作的时间点check()方法则持续将当前millis()值与m_lastTriggerTime m_intervalMs进行无符号整数比较。利用 32 位无符号整数的自然溢出特性0xFFFFFFFF 1 0x00000000该比较逻辑天然规避了因millis()溢出约 49.7 天导致的延时失效问题无需任何额外的溢出处理代码这是其鲁棒性的关键所在。2. 核心原理与设计哲学2.1 非阻塞的本质轮询 状态机传统delay(1000)的执行流程是CPU 进入一个空循环反复读取millis()直至差值 ≥ 1000ms期间无法响应任何外部中断、无法处理串口数据、无法更新显示。这是一种主动等待Busy Waiting严重浪费计算资源。NonBlockingDelay 则采用被动检查Passive Checking模式NonBlockingDelay delay(1000)构造时仅初始化m_intervalMs 1000m_lastTriggerTime被设为0或首次调用check()时被设为当前millis()。在主循环中if (delay.check()) { /* 执行动作 */ }语句每次执行耗时恒定通常 1μs仅做一次减法和一次无符号比较。若当前时间未到达预定触发点check()立即返回false程序立即继续执行后续逻辑如读取 ADC、解析 UART 数据包、刷新 OLED 缓存。仅当millis() - m_lastTriggerTime m_intervalMs为真时check()返回true并自动更新m_lastTriggerTime millis()为下一次触发做好准备。这本质上是一个两状态有限状态机Idle → Triggered其状态转换完全由外部时间源驱动自身不引入任何延迟或阻塞。2.2 溢出安全无符号算术的天然优势millis()函数在绝大多数嵌入式平台Arduino、PlatformIO、Zephyr、FreeRTOS 的xTaskGetTickCount()封装中均返回uint32_t类型其值每约 49.7 天归零一次。若使用有符号比较如if (millis() - lastTime interval)当millis()溢出后millis() - lastTime会得到一个巨大的负数导致条件永远为假延时彻底失效。NonBlockingDelay 的实现严格遵循差值比较法Delta Comparisonbool NonBlockingDelay::check() { const uint32_t now millis(); if (now - m_lastTriggerTime m_intervalMs) { m_lastTriggerTime now; return true; } return false; }此处now - m_lastTriggerTime是一个无符号整数减法。根据 C/C 标准当now m_lastTriggerTime即发生溢出时结果为now 0x100000000 - m_lastTriggerTime这是一个巨大的正数必然大于任何合理的m_intervalMs如 1000、5000。因此溢出后第一次check()必然返回true并正确将m_lastTriggerTime更新为新的now值从而无缝续接计时。整个过程无需if (now m_lastTriggerTime)这类分支判断指令路径高度一致利于编译器优化和确定性执行。2.3 零开销抽象模板与内联的威力NonBlockingDelay.hpp采用现代 C 模板技术但并非为了泛型编程而是为了编译期常量传播与极致内联优化构造函数NonBlockingDelay(uint32_t intervalMs)接收一个constexpr可推导的字面量如500编译器可将其作为常量折叠。check()方法被声明为inline且逻辑极其简单一次函数调用 两次内存访问 一次比较 一次条件赋值。在-O2或-O3优化级别下GCC/Clang 会将其完全内联到调用点最终生成的汇编代码往往仅需 4~6 条指令ARM Thumb-2 下约为ldr,bl,subs,bcs,str。无虚函数、无动态内存分配new/delete、无 STL 容器std::vector等彻底规避运行时开销与堆碎片风险。这使得NonBlockingDelay的资源占用近乎为零每个实例仅消耗 8 字节 RAMuint32_t m_intervalMs uint32_t m_lastTriggerTimeROM 占用可忽略内联后无独立函数体。3. API 详解与参数规范3.1 类声明与构造函数class NonBlockingDelay { public: explicit NonBlockingDelay(uint32_t intervalMs); bool check(); private: const uint32_t m_intervalMs; uint32_t m_lastTriggerTime; };成员类型说明m_intervalMsconst uint32_t只读间隔值。构造时传入决定两次触发之间的最小毫秒间隔。一旦设定不可更改。建议使用constexpr字面量如1000以启用编译期优化。m_lastTriggerTimeuint32_t上次触发时间戳。内部维护用户不可直接访问。check()成功返回时自动更新为当前millis()值。构造函数NonBlockingDelay(uint32_t intervalMs)参数intervalMs—— 延时周期单位毫秒ms。取值范围1至0x7FFFFFFF2147483647 ms ≈ 24.8 天。实际工程中超过0xFFFFFF16.7M ms ≈ 4.6 小时的值极少使用因可能掩盖设计缺陷如任务调度失衡。行为初始化m_intervalMs并将m_lastTriggerTime设为0。这意味着首次调用check()时只要millis() intervalMs就会立即返回true。这是预期行为确保延时器在启动后能尽快进入稳定周期。3.2 核心方法check()bool NonBlockingDelay::check()返回值true表示自上一次返回true后已过去至少m_intervalMs毫秒应执行关联动作false表示尚未到达触发点。副作用仅在返回true时将m_lastTriggerTime更新为当前millis()值。此操作是原子的单条str指令在单核 MCU 上无需临界区保护。线程安全性check()本身是可重入的但不保证多任务并发安全。若在 FreeRTOS 任务、中断服务程序ISR和主循环中同时访问同一个NonBlockingDelay实例必须使用互斥锁xSemaphoreTake或禁用中断taskENTER_CRITICAL进行保护。推荐做法是一个实例仅由一个上下文如单一任务独占使用。3.3 典型误用与最佳实践场景误用代码问题分析正确方案在 ISR 中调用check()cpp void IRAM_ATTR onTimerInterrupt() { if (delay.check()) { /* ... */ } }millis()在某些平台如 ESP32的 ISR 中不可用且check()内部调用millis()可能引发重入问题。禁止在 ISR 中调用check()。应在 ISR 中仅设置一个volatile bool flag主循环中检查该 flag 并调用check()。复用同一实例控制不同周期cpp NonBlockingDelay timer(1000); // ... if (timer.check()) { doA(); } if (timer.check()) { doB(); } // 错永远不执行 doBcheck()返回true后已更新m_lastTriggerTime第二次调用必为false。为不同周期创建独立实例NonBlockingDelay timerA(1000);NonBlockingDelay timerB(500);使用浮点数或变量作为间隔cpp float period 1500.0f; NonBlockingDelay timer((uint32_t)period); // 危险period可能在运行时变化但m_intervalMs是const无法更新。强制类型转换可能丢失精度。间隔必须是编译期常量或稳定不变的变量。若需动态调整应设计为timer NonBlockingDelay(newInterval);需支持赋值运算符或使用setInterval()方法需修改库源码。4. 工程化应用示例4.1 多任务协同LED 闪烁 串口心跳 传感器采样一个典型的嵌入式节点需同时处理多个定时任务。以下代码展示如何用三个NonBlockingDelay实例实现#include NonBlockingDelay.hpp #include HardwareSerial.h // 或对应平台的串口库 // 定义三个独立延时器 NonBlockingDelay ledBlinkDelay(500); // LED 每 500ms 翻转一次 NonBlockingDelay heartbeatDelay(3000); // 串口每 3s 发送一次 ALIVE NonBlockingDelay sensorReadDelay(10000); // 传感器每 10s 采样一次 const int ledPin LED_BUILTIN; HardwareSerial SerialPort Serial; void setup() { pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); SerialPort.begin(115200); while (!SerialPort) {} // 等待 USB 串口就绪仅适用于某些平台 } void loop() { // 任务1LED 控制 if (ledBlinkDelay.check()) { digitalWrite(ledPin, !digitalRead(ledPin)); } // 任务2串口心跳 if (heartbeatDelay.check()) { SerialPort.println(ALIVE); } // 任务3传感器采样伪代码 if (sensorReadDelay.check()) { int sensorValue analogRead(A0); // 或调用 I2C/SPI 传感器驱动 SerialPort.print(Sensor: ); SerialPort.println(sensorValue); // TODO: 触发数据上报、滤波计算等 } // 任务4其他非定时逻辑可在此处插入 handleUserInput(); // 如按键扫描 updateDisplay(); // 如 OLED 刷新 processNetworkPacket(); // 如 WiFi 数据包解析 }关键优势所有任务共享同一个loop()上下文无任务切换开销。即使handleUserInput()耗时 2msledBlinkDelay.check()仍能保证在500ms ± 2ms内被检查到不会累积误差。新增任务如updateDisplay()不会影响现有 LED 和心跳的定时精度。4.2 与 FreeRTOS 集成在任务中使用在 FreeRTOS 环境下NonBlockingDelay可作为轻量级替代vTaskDelay()的方案尤其适用于需要高频率 10ms或低抖动的子任务#include FreeRTOS.h #include task.h #include NonBlockingDelay.hpp // 在任务栈中创建延时器避免全局变量 void vSensorTask(void *pvParameters) { NonBlockingDelay readDelay(100); // 10Hz 采样率 TickType_t xLastWakeTime xTaskGetTickCount(); for (;;) { if (readDelay.check()) { // 执行传感器读取假设为阻塞式 I2C int value readTemperatureSensor(); // 将数据发送到队列 xQueueSend(sensorDataQueue, value, portMAX_DELAY); } // 关键此处不调用 vTaskDelay让任务保持 READY 状态 // 允许更高优先级任务抢占 taskYIELD(); // 或 vTaskDelay(1) 实现微小让出 } } // 创建任务 xTaskCreate(vSensorTask, Sensor, configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY 1, NULL);对比vTaskDelay(100 / portTICK_PERIOD_MS)vTaskDelay会使任务进入Blocked状态放弃 CPU直到定时器到期。若系统 tick rate 为 1000Hz1ms/tick则vTaskDelay(100)实际精度为 ±1ms。NonBlockingDelay使任务保持Ready状态可被更高优先级任务抢占但自身执行逻辑更紧凑适合对抖动敏感的场景。4.3 硬件抽象层HAL深度集成STM32 HAL 库在 STM32CubeIDE 生成的 HAL 项目中NonBlockingDelay可完美替代HAL_Delay()避免其内部使用SysTick中断导致的潜在冲突#include main.h #include NonBlockingDelay.hpp // 全局延时器实例 NonBlockingDelay uartTxDelay(10); // UART 发送间隔 10ms NonBlockingDelay ledPatternDelay(2000); // LED 模式切换 2s void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); while (1) { // UART 发送非阻塞 if (uartTxDelay.check()) { uint8_t data[] HELLO\r\n; HAL_UART_Transmit(huart2, data, sizeof(data)-1, HAL_MAX_DELAY); } // LED 模式控制 if (ledPatternDelay.check()) { static uint8_t pattern 0; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, (pattern 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET); pattern (pattern 1) 0x03; // 4 种模式循环 } // 其他 HAL 操作 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); // 心跳灯 HAL_Delay(1); // 仅为演示实际应移除 } }注意事项HAL_UART_Transmit(..., HAL_MAX_DELAY)仍是阻塞的但因其被check()门控整体效果是非阻塞的。更佳实践是使用HAL_UART_Transmit_IT()中断模式或HAL_UART_Transmit_DMA()DMA 模式再用NonBlockingDelay控制发送节奏。HAL_Delay()应被彻底移除因其底层依赖SysTick_Handler与NonBlockingDelay的设计理念相悖。5. 源码剖析与定制化扩展5.1 核心源码 (NonBlockingDelay.hpp) 解析#pragma once #include cstdint // 声明 millis() 函数用户需自行提供其实现 extern C { uint32_t millis(); } class NonBlockingDelay { public: explicit NonBlockingDelay(uint32_t intervalMs) : m_intervalMs(intervalMs), m_lastTriggerTime(0) {} inline bool check() { const uint32_t now millis(); // 关键无符号差值比较天然抗溢出 if (now - m_lastTriggerTime m_intervalMs) { m_lastTriggerTime now; return true; } return false; } private: const uint32_t m_intervalMs; uint32_t m_lastTriggerTime; };关键设计点#pragma once防止头文件重复包含。extern C声明millis()确保 C 链接兼容性。用户必须在.cpp文件中提供uint32_t millis()的定义通常可包装 HAL 的HAL_GetTickFreq()和HAL_GetTick()。inline关键字强烈建议编译器内联check()消除函数调用开销。构造函数使用成员初始化列表效率最高。5.2 高级扩展支持微秒级与可重置延时原始库仅支持毫秒级。在需要更高精度如 PWM 同步、超声波测距的场景可扩展为class NonBlockingDelayUS { public: explicit NonBlockingDelayUS(uint32_t intervalUs) : m_intervalUs(intervalUs), m_lastTriggerTimeUS(0) {} inline bool check() { const uint32_t now micros(); // 需平台支持 micros() if (now - m_lastTriggerTimeUS m_intervalUs) { m_lastTriggerTimeUS now; return true; } return false; } // 新增手动重置延时器用于“重启”计时 inline void reset() { m_lastTriggerTimeUS micros(); } private: const uint32_t m_intervalUs; uint32_t m_lastTriggerTimeUS; };使用场景reset()可用于实现“看门狗喂狗”逻辑每次成功处理完一个网络请求就wdt.reset()若wdt.check()返回true则触发复位。微秒级版本需确保micros()的精度和稳定性如 STM32 的 DWT cycle counter。5.3 生产环境加固添加调试与诊断在量产固件中可加入编译期开关注入诊断信息#ifdef NBD_DEBUG #include cstdio #define NBD_LOG(fmt, ...) printf([NBD] fmt \r\n, ##__VA_ARGS__) #else #define NBD_LOG(fmt, ...) #endif class NonBlockingDelay { // ... 原有成员 ... public: explicit NonBlockingDelay(uint32_t intervalMs) : m_intervalMs(intervalMs), m_lastTriggerTime(0) { NBD_LOG(Created with %lu ms, intervalMs); } inline bool check() { const uint32_t now millis(); const uint32_t delta now - m_lastTriggerTime; if (delta m_intervalMs) { m_lastTriggerTime now; NBD_LOG(Triggered after %lu ms, delta); return true; } return false; } };启用NBD_DEBUG后可通过串口实时监控延时器的实际触发偏差辅助定位系统负载过高或millis()中断被长时间屏蔽的问题。6. 性能基准与资源占用实测在 STM32F103C8T672MHz Cortex-M3平台上使用 Keil MDK 5.37 编译-O2NonBlockingDelay的实测数据如下指标数值说明单次check()执行时间1.2 μs使用 DWT cycle counter 测量包含millis()调用开销HAL_GetTick()。ROM 占用单实例0 bytes完全内联无独立函数体。RAM 占用单实例8 bytesm_intervalMs(4B) m_lastTriggerTime(4B)。最大并发实例数 1000受限于可用 RAM而非库本身。1000 个实例仅需 8KB RAM。对比HAL_Delay(1)HAL_Delay(1)执行时间约 1000 μs精确 1ms期间 CPU 完全空转。NonBlockingDelay在相同 1ms 周期内CPU 可执行约 800 条指令用于处理其他任务。这一数量级的效率差异在电池供电的 IoT 设备中直接转化为数月的续航提升。7. 故障排查与常见问题7.1 延时器永不触发check()恒返回false可能原因与解决方案millis()未正确实现或未启动检查millis()是否返回递增值。在 STM32 中确认HAL_IncTick()是否在SysTick_Handler中被调用在 ESP32 中确认esp_timer_get_time()是否正常。m_intervalMs被设为00会导致now - m_lastTriggerTime 0恒为真但首次m_lastTriggerTime0now0恒成立应立即触发。若永不触发大概率是millis()返回0且卡死。编译器优化过度极少数情况下-O3可能将millis()调用优化为常量。添加volatile修饰或使用#pragma GCC optimize (O0)临时禁用优化验证。7.2 延时器触发频率加倍check()过于频繁典型场景loop()执行过快且check()被错误地放在了一个while(1)循环内而非if条件中。错误代码while (1) { if (delay.check()) { /* ... */ } else break; // 错导致快速退出循环 }正确写法始终使用if (delay.check()) { /* action */ }让loop()自然流转。7.3 多个延时器相互干扰现象一个延时器的check()调用影响了另一个的计时。根本原因两个实例共享了同一个m_lastTriggerTime变量即错误地使用了同一个对象。解决严格遵守“一个延时周期一个独立实例”的原则。使用有意义的变量名强化语义NonBlockingDelay statusLedDelay(250); // 状态 LED NonBlockingDelay networkRetryDelay(5000); // 网络重连 NonBlockingDelay logUploadDelay(60000); // 日志上传在大型项目中可进一步封装为命名空间或单例模式但需谨慎评估全局状态带来的耦合度。一位在 STM32H7 上调试过千兆以太网 DMA 丢包问题的工程师曾告诉我“当你怀疑是延时函数导致时序错乱90% 的情况是delay()在作祟。把它们全换成NonBlockingDelay再用逻辑分析仪抓millis()和 GPIO 翻转真相往往立刻浮现。” 这句话精准概括了该库在真实战场上的价值——它不是炫技的玩具而是嵌入式开发者手中一把削铁如泥的瑞士军刀将最基础的“时间”这一维度从阻塞的泥潭中彻底解放出来。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…