时间轴
工作流程
用户空闲 > idle_delay_ms → 远程命令到达 → ProcessCommandQueue 获取锁
│
设置 MODEMACRO = "远程协作同步中..."
│
while 循环处理命令
│
每条命令执行前检查 m_userIsActive
│
┌─ 用户开始操作 → re-queue 剩余命令 → break
│
└─ 用户仍空闲 → 继续执行
│
恢复 MODEMACRO 原值
服务器(无状态,纯转发)
│
│ 广播 "MOVE 实体 A"
│
├──→ 用户B 的 AutoCAD 插件
│ └── m_commandQueue: [MOVE A]
│ └── 空闲 → 执行
│
├──→ 用户C 的 AutoCAD 插件
│ └── m_commandQueue: [MOVE A]
│ └── 操作中 → re-queue → 等空闲
│
└──→ 用户D 的 AutoCAD 插件
└── m_commandQueue: [MOVE A]
└── 空闲 → 执行
发送方 → WebSocket 服务器 → 广播给所有接收方
│
┌───────────┼───────────┐
▼ ▼ ▼
用户B 用户C 用户D
(空闲,执行) (操作中,入队) (空闲,执行)
ExecuteRemoteCommand(msg)
│
├─ 1. acDocManager->lockDocument(doc) ← 获取写锁
│ │
│ └─ 如果用户正在绘图 → 锁已被用户持有 → 失败,返回 false
│
├─ 2. 创建/修改实体(写数据库)
│
└─ 3. acDocManager->unlockDocument(doc) ← 释放写锁
commandWillStart
┌──────────────────────────────────────┐
│ │
▼ │
USER_ACTIVE ──(1s无操作)──> PROCESSING ──(用户开始操作)──┐
▲ │ │
│ ▼ │
│ 队列处理完毕 │
│ │ │
└──────────────────────────┘──────────────────────────┘| 接收方 | 状态 | 行为 |
|---|---|---|
| 用户 B(空闲) | lockDocument 成功 | 立即执行 ✅ |
| 用户 C(操作中) | lockDocument 失败 | re-queue,等空闲后重试 ⏳ |
| 用户 D(空闲) | lockDocument 成功 | 立即执行 ✅ |
锁冲突的本质
| 场景 | 锁持有者 | 远程命令 |
|---|---|---|
| 用户空闲 | 无人持锁 | lockDocument 成功,正常执行 |
| 用户正在画线 | 用户命令持锁 | lockDocument 失败,返回 false → re-queue |
| 远程命令执行中 | 远程命令持锁 | 用户点击 → 用户等待锁释放 |
所以我们不能”不锁定”,只能”选择合适的时机去锁定”。 这就是你之前说的”用户优先”原则——用户操作时我们不抢锁,等用户空闲 1s 后再尝试获取锁执行远程命令。
作者:秦晓川 创建时间:2026-06-19 15:00
最后编辑:秦晓川 更新时间:2026-07-05 22:55
最后编辑:秦晓川 更新时间:2026-07-05 22:55