docs(规范,门禁): 卷锁五态去裸形——本仓第一次真正还第二根护栏的债,并写清还债的算法
最反直觉的是结果里的差值:36 处裸形态号全部清零,绝对数只从 1,162 降到 1,156(−6,余量 4 → 10 格)。 作者没把差值糊过去而是查到底:check_ids 只在字面量**落不进任何已登记族**时才计不可判定,撞进已登记族的 23 处本来就记在可判定侧,删它们分子分母同缩、比例反而从 86.74% 涨到 86.77%;真正在盲区里的只有族外 7 处,其中 1 处还被变更记录行豁免 ⇒ 账面 −6,算式对平(±1 属同窗别道在飞)。**这四条机制我写进 docs/门禁说明/id-check.md §6.10 并署名作者**——它是「怎么还这根护栏的债」的第一份操作口径。 改动面:App/fs/vol_lock.c 10 处、.h 6 处、vol_lock_test.c 14 处、卷锁单元测试说明.md 3 处 ⇒ 同口径 改后 0 处。四态语义只留 vol_lock.h 的 vol_lock_stats_t 注释一处,其余三处只描述断言并指回头文件, 不抄第二真源。除 4 行声明外全是注释文字,代码行为零改动。顺带消掉一个**同形两义**的撞号源。 实测:1,162(03:15:08)→ 1,156(03:21:56),写变更记录后复量仍 1,156(本笔没吃余量);--strict exit 0;vol_lock 套件 45/45;**上限未动、刻意不跑 --update-baseline**(作者反对成立:重锚会把只减不增的线 按这次 −6 重画,白丢一次真还债的账面记录);未改 id_registry.json / 台账,未跑 --all-files。
This commit is contained in:
+10
-9
@@ -6,7 +6,8 @@
|
||||
* 创建日期:2026-10-02
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-02 王建锋 创建
|
||||
* v1.1 2026-10-26 DTU 项目组 道G task-17:① 新增 4 个观测计数(T-a/T2/T3/T4,
|
||||
* v1.1 2026-10-26 DTU 项目组 道G task-17:① 新增 4 个观测计数(持锁 / try 超时 /
|
||||
* 分片退让 / 零互斥 四态,
|
||||
* 共 16 B 静态)与 vol_lock_get_stats() 只读口 —— 不取锁、
|
||||
* 零外部调用、零局部变量,13 处调用点一字未动;
|
||||
* ② 修 :38「返回值」注释与代码相反的错(fail-open 原被
|
||||
@@ -34,10 +35,10 @@ static osMutexId_t s_lock; /* 卷串行化互斥锁(vol_lock_init 创建)
|
||||
* 并发:多个任务可同时自增同一个计数,竞态下少计不会多计(判据是"是否 > 0 / 是否还
|
||||
* 在增长",不是精确值),所以不为此上临界区 —— 上临界区反倒把观测做成了故障本身。
|
||||
* volatile:跨任务读写且无锁保护,禁止把读侧重复读优化掉。 */
|
||||
static volatile uint32_t s_st_acquired; /* T-a 真取到互斥 */
|
||||
static volatile uint32_t s_st_try_timeout; /* T2 try(timeout=0)失败:卷被别人占住 */
|
||||
static volatile uint32_t s_st_blk_timeout; /* T3 分片等待超时:ftpTask 正常退让 */
|
||||
static volatile uint32_t s_st_failopen; /* T4 锁不存在却返 1:谎报成功那一态 */
|
||||
static volatile uint32_t s_st_acquired; /* 持锁态:真取到互斥(四态定义见 vol_lock.h) */
|
||||
static volatile uint32_t s_st_try_timeout; /* try 超时态:timeout=0 没取到,卷被别人占住 */
|
||||
static volatile uint32_t s_st_blk_timeout; /* 分片退让态:分片等待超时,ftpTask 正常退让 */
|
||||
static volatile uint32_t s_st_failopen; /* 零互斥态:锁不存在却返 1,谎报成功那一态 */
|
||||
|
||||
/* 函数定义区 */
|
||||
|
||||
@@ -73,18 +74,18 @@ int vol_lock_wait(uint32_t timeout_ms) {
|
||||
if (s_lock == NULL) {
|
||||
(void)vol_lock_init();
|
||||
if (s_lock == NULL) {
|
||||
s_st_failopen++; /* T4:返 1 但零互斥 —— 谎报成功那一态 */
|
||||
s_st_failopen++; /* 零互斥态:返 1 但零互斥 —— 谎报成功那一态 */
|
||||
return 1; /* 锁创建失败:fail-open(不阻塞,保持启动段可用) */
|
||||
}
|
||||
}
|
||||
if (osMutexWait(s_lock, timeout_ms) == osOK) {
|
||||
s_st_acquired++; /* T-a:真持锁 */
|
||||
s_st_acquired++; /* 持锁态:真持锁 */
|
||||
return 1;
|
||||
}
|
||||
if (timeout_ms == 0u) {
|
||||
s_st_try_timeout++; /* T2:压根没等(喂狗点/绘制路径只有这一态会发生) */
|
||||
s_st_try_timeout++; /* try 超时态:压根没等(喂狗点/绘制路径只有这一态会发生) */
|
||||
} else {
|
||||
s_st_blk_timeout++; /* T3:等了一会儿没等到(分片退让),语义与 T2 不同 */
|
||||
s_st_blk_timeout++; /* 分片退让态:等了一会儿没等到,与 try 超时态语义不同 */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+8
-7
@@ -72,13 +72,14 @@ int vol_lock_wait(uint32_t timeout_ms);
|
||||
|
||||
/*
|
||||
* 卷锁观测计数(道G task-17「卷锁 5 态可观测性」)。四个字段就是四态,语义**不得**合并:
|
||||
* T-a `acquired` = 真取到互斥的次数
|
||||
* T2 `try_timeout` = timeout=0 的 try 失败次数(卷被别的任务占住;defaultTask/uiTask
|
||||
* 的喂狗与绘制路径只有这一态会发生)
|
||||
* T3 `blk_timeout` = timeout>0 的分片等待超时次数(ftpTask 100 ms 分片正常退让,
|
||||
* 语义与 T2 不同:那是"等了一会儿没等到",这是"压根没等")
|
||||
* T4 `failopen` = 锁不存在却返 1 的次数(**谎报成功**那一态,见 wait 的函数头)
|
||||
* T1「从未调用过」不占计数:三个计数全 0 就说明这条路径没跑过——区分"没跑过"与
|
||||
* `acquired` 持锁态 = 真取到互斥的次数
|
||||
* `try_timeout` try 超时态 = timeout=0 的 try 失败次数(卷被别的任务占住;
|
||||
* defaultTask/uiTask 的喂狗与绘制路径只有这一态会发生)
|
||||
* `blk_timeout` 分片退让态 = timeout>0 的分片等待超时次数(ftpTask 100 ms 分片正常
|
||||
* 退让;与 try 超时态语义不同:那是"等了一会儿没等到",
|
||||
* 这是"压根没等")
|
||||
* `failopen` 零互斥态 = 锁不存在却返 1 的次数(**谎报成功**那一态,见 wait 函数头)
|
||||
* 「未调用」这一态不占计数:三个计数全 0 就说明这条路径没跑过——区分"没跑过"与
|
||||
* "跑了但一直忙"正是本卡的目的(此前两者在日志上完全一样)。
|
||||
* ⚠ 本层**刻意不记时刻**:记时刻就得读 tick,等于给 defaultTask 的取锁链添一个
|
||||
* callee 与几字节帧,而这条链的余量我们整天都在省着花(诊断不值那几个字节)。
|
||||
|
||||
Reference in New Issue
Block a user