news 2026/9/20 1:39:57

CANN Runtime CntNotify(计数型通知)管理接口详解:创建、记录、等待与销毁全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN Runtime CntNotify(计数型通知)管理接口详解:创建、记录、等待与销毁全指南
  • CANN
  • Ascend
  • 人工智能
  • 任务调度

【免费下载链接】runtime

本项目提供CANN运行时组件和维测功能组件。

项目地址:https://gitcode.com/cann/runtime
点击查看免费下载

导读

本文聚焦 CANN Runtime 提供的 CntNotify(计数型通知)管理接口,系统讲解aclrtCntNotifyCreateaclrtCntNotifyRecordaclrtCntNotifyWaitWithTimeoutaclrtCntNotifyResetaclrtCntNotifyGetIdaclrtCntNotifyDestroy六个接口的声明、参数、行为模式与适用场景,并深入仓库源码揭示其底层实现链路(ACL 封装层 → RTS 运行时 API →CountNotify内核对象)。读完本文,你将掌握如何利用计数值实现多 Stream 之间、乃至 Device 之间的复杂同步等待逻辑,并理解 CntNotify 与传统 Notify 在计数能力上的本质差异。

适用前提:本组接口目前仅在Ascend 950PR / Ascend 950DT产品上支持,其余 Atlas 系列产品与 IPV350 均不支持,开发前请先确认目标硬件平台。


一、CntNotify 概述:与 Notify 的本质区别

CntNotify(Count Notify,计数型通知)是 CANN Runtime 中用于任务同步的通知原语。官方文档(docs/zh/api_ref/09_cntNotify_management.md)明确指出:CntNotify 通常也用于 Device 与 Device 之间的状态/动作通信通知,但它是利用计数值实现任务间的同步

它与普通 Notify 的核心区别在于计数值能力:

对比项NotifyCntNotify
计数值范围仅支持1支持[1 ~ uint32_t 最大值]
同步粒度单一信号量(置位/等待)可基于数值比较、位运算实现多条件同步
典型场景Event/Notify 置位等待多 Stream 计数同步、Device 间状态通知

由于计数值可以累加、覆盖、按位运算,CntNotify 天然适合“等待 N 次事件完成后再继续”这类需要计数语义的场景,而不仅仅是一次性的信号通知。

从类型定义看,aclrtCntNotifyaclrtNotifyaclrtStream一样是不透明句柄(见 docs/zh/api_ref/25-05_Typedefs.md 与 include/external/acl/acl_base_rt.h):

typedef void* aclrtCntNotify;

开发者无需关心句柄内部结构,只需通过本组管理接口完成创建、记录、等待、复位、查询与销毁。


二、产品支持情况(务必先确认平台)

以下产品支持情况直接引用官方文档(docs/zh/api_ref/09_cntNotify_management.md)与源码中 arch5162 等平台的接口裁剪定义(src/runtime/cmake/arch5162_unsupported_acl_api.def):

产品CntNotify 支持情况
Ascend 950PR / Ascend 950DT✅ 支持
Atlas A3 训练系列产品 / Atlas A3 推理系列产品❌ 不支持
Atlas A2 训练系列产品 / Atlas A2 推理系列产品❌ 不支持
Atlas 200I/500 A2 推理产品❌ 不支持
Atlas 推理系列产品❌ 不支持
Atlas 训练系列产品❌ 不支持
IPV350❌ 不支持

也就是说,CntNotify 目前是 Ascend 950 系列专属能力。在非 950 平台上调用这些接口将返回失败,代码中需要做好平台兼容判断或错误处理。


三、CntNotify 相关的枚举与结构体

在讲解接口前,先掌握两个关键枚举(定义于 include/external/acl/acl_rt.h,文档说明见 docs/zh/api_ref/25-02_Enumerations.md)和两个结构体(定义见 docs/zh/api_ref/25-04_Structs.md)。

3.1 Record 行为模式:aclrtCntNotifyRecordMode

typedef enum { ACL_RT_CNT_NOTIFY_RECORD_SET_VALUE_MODE = 0, // 覆盖模式,CntNotify计数值 = value ACL_RT_CNT_NOTIFY_RECORD_ADD_MODE = 1, // 累加模式,CntNotify计数值 = 当前值 + value ACL_RT_CNT_NOTIFY_RECORD_BIT_OR_MODE = 2, // bit或模式,CntNotify计数值 = 当前值 | value ACL_RT_CNT_NOTIFY_RECORD_BIT_AND_MODE = 4, // bit与模式,CntNotify计数值 = 当前值 & value } aclrtCntNotifyRecordMode;
  • SET_VALUE(覆盖):直接将计数值写为value,适合对 CntNotify 重新初始化。
  • ADD(累加):每次 Record 使计数值增加value,是实现“N 次事件计数”的常用模式。
  • BIT_OR / BIT_AND(位运算):按位写入或清除位,可与下方 Wait 的位掩码模式配合实现多信号位同步。

3.2 Wait 行为模式:aclrtCntNotifyWaitMode

typedef enum { ACL_RT_CNT_NOTIFY_WAIT_LESS_MODE = 0, // 当前计数值 < value,则解除Wait ACL_RT_CNT_NOTIFY_WAIT_EQUAL_MODE = 1, // 当前计数值 = value,则解除Wait ACL_RT_CNT_NOTIFY_WAIT_BIGGER_MODE = 2, // 当前计数值 > value,则解除Wait ACL_RT_CNT_NOTIFY_WAIT_BIGGER_OR_EQUAL_MODE = 3, // 当前计数值 >= value,则解除Wait ACL_RT_CNT_NOTIFY_WAIT_EQUAL_WITH_BITMASK_MODE = 4, // 当前计数值 & value = value,则解除Wait } aclrtCntNotifyWaitMode;

五种模式覆盖了数值比较(小于、等于、大于、大于等于)与位掩码匹配,配合 Record 的不同写入模式,可构造出非常灵活的同步条件。

3.3 结构体:aclrtCntNotifyRecordInfoaclrtCntNotifyWaitInfo

typedef struct { aclrtCntNotifyRecordMode mode; // Record的行为模式 uint32_t value; } aclrtCntNotifyRecordInfo;
typedef struct { aclrtCntNotifyWaitMode mode; // Wait的行为模式 uint32_t value; uint32_t timeout; // 超时时间,单位是秒,其中,0表示永久等待 uint8_t isClear; // wait解除阻塞后是否将CntNotify的计数值自动清空为0,取值:1表示清空,0表示不清空 uint8_t rev[3]; // 预留字节 } aclrtCntNotifyWaitInfo;

几个关键点的使用提示:

  • timeout:单位为秒,0表示永久等待。这是aclrtCntNotifyWaitWithTimeout名称中 "WithTimeout" 的由来,也是防止同步条件永远不满足时死等的关键防护。
  • isClear:解除等待后是否自动清零计数值。多轮复用同一个 CntNotify 时建议置1,避免上一轮的计数残留影响下一轮同步。
  • rev[3]:预留字段,固定填 0 即可。

四、接口详解(六大管理接口)

以下六个接口按“创建 → 记录 → 等待 → 复位 → 查询 → 销毁”的生命周期顺序展开。所有接口的返回值约定一致:返回 0 表示成功,返回其他值表示失败,具体错误码含义请参见 aclError。

4.1 aclrtCntNotifyCreate:创建 CntNotify

aclError aclrtCntNotifyCreate(aclrtCntNotify *cntNotify, uint64_t flag)

功能说明:创建 CntNotify。flag 为预留参数,当前必须固定配置为 0。这一点在底层实现中也有强校验——在 src/runtime/api/api_david.cc 中,rtCntNotifyCreateServerflags != 0ULL的情况直接返回RT_ERROR_INVALID_VALUE

COND_RETURN_EXT_ERRCODE_AND_MSG_OUTER_WITH_PARAM(flags != 0ULL, RT_ERROR_INVALID_VALUE, flags, "0");

也就是说,flag传非 0 值会直接报参数非法。

参数说明

参数名输入/输出说明
cntNotify输出CntNotify 的指针,类型为 aclrtCntNotify。创建成功后,句柄由运行时分配并写出。
flag输入预留参数,当前固定配置为 0。

源码佐证:ACL 层封装见 src/acl/aclrt_impl/notify.cpp,内部通过rtCntNotifyCreateServer下发到 Runtime;Runtime 层再依据当前 Device 创建CountNotify内核对象,并通过driver_->NotifyIdAlloc(...)向驱动申请物理 notify ID(见 src/runtime/feature/cntnotify/count_notify.cc)。若申请不到 notify 资源,会携带错误码EE1023(“Too many CntNotify objects are created”),即创建的 CntNotify 数量过多导致资源耗尽,可参考 docs/zh/FAQ/EE1023资源不足问题.md 排查。

4.2 aclrtCntNotifyRecord:在指定 Stream 上记录 CntNotify(异步)

aclError aclrtCntNotifyRecord(aclrtCntNotify cntNotify, aclrtStream stream, aclrtCntNotifyRecordInfo *info)

功能说明:在指定 Stream 上记录一个 CntNotify,异步接口aclrtCntNotifyRecordaclrtCntNotifyWaitWithTimeout配合使用时,主要用于多 Stream 之间同步等待的场景。

参数说明

参数名输入/输出说明
cntNotify输入需记录的 CntNotify,类型见 aclrtCntNotify。
stream输入指定 Stream,类型见 aclrtStream。使用默认 Stream 时填NULL。多 Stream 同步等待场景下(例如 Stream2 等 Stream1),此处配置为Stream1(即“记录发生在哪个 Stream 上”)。
info输入控制 Record 的行为模式,见 aclrtCntNotifyRecordInfo。

源码佐证:在 src/runtime/feature/cntnotify/count_notify.cc 中,CountNotify::Record在指定 Stream 上分配TS_TASK_TYPE_NOTIFY_RECORD类型的任务,调用NotifyRecordTaskInit初始化后经DavidSendTask异步下发。注意实现中info指针不能为NULL,ACL 层通过ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(info)做了非空校验(见 src/acl/aclrt_impl/notify.cpp),传空指针会直接报输入参数错误。

4.3 aclrtCntNotifyWaitWithTimeout:阻塞 Stream 等待 CntNotify 完成(异步)

aclError aclrtCntNotifyWaitWithTimeout(aclrtCntNotify cntNotify, aclrtStream stream, aclrtCntNotifyWaitInfo *info)

功能说明:阻塞指定 Stream 的运行,直到指定的 CntNotify 满足等待条件,异步接口(阻塞的是 Stream 上的后续任务,而非调用线程)。

参数说明

参数名输入/输出说明
cntNotify输入需等待的 CntNotify,类型见 aclrtCntNotify。
stream输入指定 Stream,类型见 aclrtStream。使用默认 Stream 时填NULL。多 Stream 同步等待场景下(例如 Stream2 等 Stream1),此处配置为Stream2(即“哪个 Stream 被阻塞等待”)。
info输入控制 Wait 的行为模式,见 aclrtCntNotifyWaitInfo。

使用要点

  • 等待条件由info->mode+info->value共同决定(小于/等于/大于/大于等于/位掩码匹配)。
  • info->timeout单位秒,0表示永久等待;建议生产环境配置合理超时值,避免条件永不满足时任务永久挂起。
  • info->isClear决定解除等待后是否自动清零,多轮复用场景建议置1
  • 该接口同样对info做非空校验,见 src/acl/aclrt_impl/notify.cpp。

4.4 aclrtCntNotifyReset:复位 CntNotify(异步)

aclError aclrtCntNotifyReset(aclrtCntNotify cntNotify, aclrtStream stream)

功能说明:复位一个 CntNotify,将其计数值清空为 0,异步接口

参数说明

参数名输入/输出说明
cntNotify输入待复位的 CntNotify,类型见 aclrtCntNotify。
stream输入指定 Stream,类型见 aclrtStream。使用默认 Stream 时填NULL

使用要点:与WaitInfo.isClear的“等待解除后自动清零”不同,Reset显式、主动的复位动作,适用于在同步周期开始时将计数值归零、重新开始一轮计数。多轮流水线场景建议在每轮开始前调用 Reset,确保计数起点一致。

4.5 aclrtCntNotifyGetId:获取 CntNotify 的 ID

aclError aclrtCntNotifyGetId(aclrtCntNotify cntNotify, uint32_t *notifyId)

功能说明:获取 CntNotify 的 ID。该 ID 可用于日志打点、profiling 关联、跨模块传递标识等场景。

参数说明

参数名输入/输出说明
cntNotify输入待获取的 CntNotify,类型见 aclrtCntNotify。
notifyId输出CntNotify ID,uint32 类型。

源码佐证CountNotify内核对象持有notifyid_成员(见 src/runtime/feature/cntnotify/count_notify.hpp),GetCntNotifyId()直接返回该 ID;Runtime 层rtGetCntNotifyId通过Api::Instance()->GetCntNotifyId(...)实现(见 src/runtime/api/api_david.cc)。

4.6 aclrtCntNotifyDestroy:销毁 CntNotify

aclError aclrtCntNotifyDestroy(aclrtCntNotify cntNotify)

功能说明:销毁 CntNotify,释放其占用的驱动 notify 资源。

参数说明

参数名输入/输出说明
cntNotify输入待销毁的 CntNotify,类型见 aclrtCntNotify。

使用要点:销毁后该句柄不可再用于任何 Record/Wait 等操作。程序退出前应确保所有 CntNotify 均被销毁,否则可能造成 notify 资源泄漏,后续进程创建 CntNotify 时会因资源不足返回 EE1023 类错误。底层CountNotify析构时会将自身从当前 Device 的 CntNotify 列表移除,并调用driver_->NotifyIdFree(...)归还 notify ID(见 src/runtime/feature/cntnotify/count_notify.cc)。


五、典型用法:多 Stream 计数同步

官方文档明确指出,Record 与 WaitWithTimeout 配合是“多 Stream 之间同步等待”的标准用法。下面给出“Stream1 上完成一次记录、Stream2 上等待其完成”的完整流程骨架:

aclrtCntNotify cntNotify = nullptr; aclrtStream stream1 = nullptr; // 记录方 aclrtStream stream2 = nullptr; // 等待方 aclrtCntNotifyRecordInfo recInfo = {}; aclrtCntNotifyWaitInfo waitInfo = {}; // 1. 创建 CntNotify(flag 固定为 0) aclError ret = aclrtCntNotifyCreate(&cntNotify, 0); if (ret != 0) { /* 处理错误 */ } // 2. 创建两个 Stream ret = aclrtCreateStream(&stream1); ret = aclrtCreateStream(&stream2); // 3. 在 Stream1 上记录一次计数:累加模式,每次 +1 recInfo.mode = ACL_RT_CNT_NOTIFY_RECORD_ADD_MODE; recInfo.value = 1; ret = aclrtCntNotifyRecord(cntNotify, stream1, &recInfo); // 4. 在 Stream2 上等待计数值 >= 1;超时 10 秒,解除后自动清零 waitInfo.mode = ACL_RT_CNT_NOTIFY_WAIT_BIGGER_OR_EQUAL_MODE; waitInfo.value = 1; waitInfo.timeout = 10; // 0 表示永久等待 waitInfo.isClear = 1; // 1 表示解除后清空计数值 ret = aclrtCntNotifyWaitWithTimeout(cntNotify, stream2, &waitInfo); // 5. 查询 ID(用于日志/profiling 关联) uint32_t notifyId = 0; ret = aclrtCntNotifyGetId(cntNotify, &notifyId); // 6. 复位并复用(可选) ret = aclrtCntNotifyReset(cntNotify, stream2); // 7. 销毁 ret = aclrtCntNotifyDestroy(cntNotify);

关键参数记忆法(官方文档原话逻辑):

  • Record 的stream是“被记录事件发生的 Stream”——Stream2 等 Stream1 时填Stream1
  • Wait 的stream是“被阻塞的 Stream”——Stream2 等 Stream1 时填Stream2
  • 使用默认 Stream 时,stream均填NULL

如果需要对“N 个生产者 Stream 都完成一轮任务后再继续”,可以让每个生产者 Stream 各执行一次ACL_RT_CNT_NOTIFY_RECORD_ADD_MODE的 Record,等待方在目标 Stream 上使用BIGGER_OR_EQUAL模式等待计数值达到 N,这正是普通 Notify 无法表达的计数同步语义。


六、底层实现链路与测试验证

6.1 调用链全景

从调用方到内核对象的完整链路如下:

应用代码 │ aclrtCntNotifyCreate / Record / WaitWithTimeout / Reset / GetId / Destroy ▼ ACL 封装层(src/acl/aclrt_impl/notify.cpp) │ ACL_PROFILING_REG 注册 profiling 埋点 + ACL_LOG_INFO 日志 │ 参数非空校验(ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT) ▼ RTS 运行时 API 层(src/runtime/api/api_david.cc) │ GLOBAL_STATE_WAIT_IF_LOCKED() 全局状态门控 │ RT_VALIDATE_AND_UNWRAP_OBJECT 句柄解包 ▼ CountNotify 内核对象(src/runtime/feature/cntnotify/count_notify.cc) │ Setup(): NotifyIdAlloc 申请驱动 notify ID │ Record(): 分配 TS_TASK_TYPE_NOTIFY_RECORD 任务并异步下发 │ Wait(): 分配 TS_TASK_TYPE_NOTIFY_WAIT 任务并异步下发 ▼ 驱动层(NpuDriver::GetDevResAddress / NotifyIdAlloc / NotifyIdFree)

值得注意的细节:

  • 所有接口都经过全局状态门控GLOBAL_STATE_WAIT_IF_LOCKED()),保证运行时初始化/去初始化期间的调用安全。
  • 句柄解包校验RT_VALIDATE_AND_UNWRAP_OBJECT会将用户传入的aclrtCntNotify句柄安全转换为内部的CountNotify*,非法句柄会直接报错而不是产生空指针崩溃。
  • 任务类型分离:Record 与 Wait 分别对应TS_TASK_TYPE_NOTIFY_RECORDTS_TASK_TYPE_NOTIFY_WAIT两种任务,任务信息结构体定义于 src/runtime/core/inc/task/task_info_struct.hpp,其中isCountNotify字段用于区分计数型通知与普通事件记录/等待。

6.2 资源类型与计数值语义

CountNotify::GetCntNotifyAddress(见 src/runtime/feature/cntnotify/count_notify.cc)揭示了内部资源划分:根据通知类型映射到不同的驱动资源,包括RT_RES_TYPE_STARS_CNT_NOTIFY_RECORD(记录)、RT_RES_TYPE_STARS_CNT_NOTIFY_ADD(累加)、RT_RES_TYPE_STARS_CNT_NOTIFY_BIT_WR(位写)、RT_RES_TYPE_STARS_CNT_NOTIFY_BIT_CLR(位清),分别对应覆盖、累加、bit 或、bit 与四种 Record 模式的底层硬件切片。

6.3 测试用例验证

仓库 UT 测试对六个接口均有覆盖(见 tests/ut/acl/testcase/acl_runtime_unittest.cpp 与 tests/ut/acl/testcase/acl_runtime_unittest.cpp),典型用例包括:

  • aclrtCntNotifyCreate/aclrtCntNotifyDestroy:验证创建与销毁调用链及 mock 转发;
  • aclrtCntNotifyRecord:以{ACL_RT_CNT_NOTIFY_RECORD_SET_VALUE_MODE, 0}构造 RecordInfo,并验证infonullptr时返回参数错误;
  • aclrtCntNotifyWaitWithTimeout:以{ACL_RT_CNT_NOTIFY_WAIT_LESS_MODE, 0, 0, true, 0}(永久等待 + 解除后清零)构造 WaitInfo,并覆盖空指针校验;
  • aclrtCntNotifyReset/aclrtCntNotifyGetId:验证复位与 ID 查询(含notifyId空指针校验)。

此外,运行时侧在 950 平台测试中有专门的rt_utest_david_event.ccrt_utest_david_stream.cc等用例(见 tests/ut/runtime/runtime/test/platform/950/ 目录),进一步印证该功能主要面向 David 架构(950 系列)实现,与文档中“仅 Ascend 950 支持”的说明一致。


七、使用建议与注意事项

  1. 平台前置检查:CntNotify 目前仅 Ascend 950PR/950DT 支持。在多平台复用的代码中,建议先用平台查询接口确认设备能力,再决定是否走 CntNotify 同步路径,避免在其他 Atlas 产品上运行时失败。
  2. flag 必须为 0aclrtCntNotifyCreateflag为预留参数,传非 0 值会被底层直接判定为非法参数(见 src/runtime/api/api_david.cc)。
  3. info 不能为空:Record 与 WaitWithTimeout 的info指针均做了非空校验,使用前务必初始化结构体(建议= {}清零)。
  4. 善用 timeout 与 isClear:Wait 的timeout建议配置有限值防止死等;isClear在多轮复用场景置 1 可免去手动 Reset,但也要注意“清零时机在解除等待之后”,若后续还有依赖旧计数值的逻辑需谨慎。
  5. 生命周期管理:CntNotify 使用完毕后必须Destroy,否则占用驱动 notify 资源,持续创建会触发 EE1023 资源不足错误;复用时注意在每轮同步周期开始前Reset归零计数值。
  6. 异步语义:Record、WaitWithTimeout、Reset 均为异步接口,它们阻塞的是 Stream 上的任务调度而非调用线程,理解这一点有助于写出不阻塞 Host 的高吞吐流水线。

参考资源

  • 接口管理文档:docs/zh/api_ref/09_cntNotify_management.md
  • 枚举定义:docs/zh/api_ref/25-02_Enumerations.md(aclrtCntNotifyRecordModeaclrtCntNotifyWaitMode
  • 结构体定义:docs/zh/api_ref/25-04_Structs.md(aclrtCntNotifyRecordInfoaclrtCntNotifyWaitInfo
  • 类型定义:docs/zh/api_ref/25-05_Typedefs.md(aclrtCntNotify
  • 错误码说明:docs/zh/api_ref/25-01_aclError.md
  • ACL 头文件声明:include/external/acl/acl_rt.h
  • ACL 封装实现:src/acl/aclrt_impl/notify.cpp
  • RTS 运行时 API:src/runtime/api/api_david.cc
  • 内核对象实现:src/runtime/feature/cntnotify/count_notify.cc 与 count_notify.hpp
  • UT 测试用例:tests/ut/acl/testcase/acl_runtime_unittest.cpp
  • CANN
  • Ascend
  • 人工智能
  • 任务调度

【免费下载链接】runtime

本项目提供CANN运行时组件和维测功能组件。

项目地址:https://gitcode.com/cann/runtime
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 1:37:27

京东校招逻辑试题解析:图形推理、数字推理与备考方法

简介&#xff1a;2019届京东校招逻辑试题是一份面向应届求职者与逻辑思维训练者的PDF文档&#xff0c;内容聚焦京东校招笔试中的逻辑类题目。资源为单个PDF文件&#xff0c;大小约229KB&#xff0c;便于下载后直接阅读或打印练习。文件内涵盖逻辑推理、数理逻辑、图形逻辑、语言…

作者头像 李华
网站建设 2026/9/20 1:36:02

投资四面体模型深度拆解:从价值投资到PDF高效阅读

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 1:32:54

SCL与UDT状态机:PLC多功能阀门标准化功能块

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 1:30:55

嵌入式人工智能实战:从传感器到端侧模型的全链路设计指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 1:30:52

PowerShell激活Windows与Office:安全审阅脚本的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 1:29:43

ENSP启动AR失败40排查与华为网络仿真实验复现指南

简介&#xff1a;名为《华为ENSP网络实验&#xff08;3&#xff09;》的PDF&#xff0c;是面向网络工程师与学习者的华为设备实验手册&#xff0c;内容围绕eNSP模拟器展开&#xff0c;覆盖交换机本地用户认证与SSH安全访问、VLAN划分及单臂路由互通、RSTP优先级与根桥保护配置、…

作者头像 李华