news 2026/9/16 20:54:34

text-to-cad并发构建保护机制:锁等待与竞态处理的工程设计细节

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
text-to-cad并发构建保护机制:锁等待与竞态处理的工程设计细节

text-to-cad并发构建保护机制:锁等待与竞态处理的工程设计细节

【免费下载链接】text-to-cadA library of agent skills for CAD, CAE and CAM项目地址: https://gitcode.com/GitHub_Trending/tex/text-to-cad

text-to-cad 是一个面向 CAD、CAE 和 CAM 的 AI Agent 技能库,它最大的特色之一,是如何在多进程同时构建同一个模型时,用一套锁等待 + 竞态处理机制保护构建过程不互相踩踏。这篇文章带你读懂它的并发保护设计:从内核级 flock 锁到超时降级,每一环都藏着工程取舍。

为什么 CAD 工作流里并发构建是"定时炸弹"?

用 Agent 生成 CAD 模型时,很容易出现这样的场景:

  • 你在 CLI 里跑了一次gen构建,AI 同时在 Viewer 里触发同一模型的构建
  • 一次构建动辄几分钟(OCP 网格化期间 GIL 会被长时间占用),两个进程如果同时写入同一目录,读者就会看到一个"写到一半"的半成品包

text-to-cad 的解法在 cadgen/coordination 包里,生产端(构建进程)和读取端(Viewer 服务器)共享同一套协议,而不是各写一份。

三个协调文件:哨兵与状态记录长什么样

每个产物的输出目录旁,都有一组"隐藏兄弟文件",定义在 coordination/paths.py 中。以输出目录<folder>/__cadgen__/models/widget.step为例:

.<name>.step.generation.lock 写者哨兵(构建时持有) .<name>.step.generator.lock 生成器哨兵(导出等不写包的操作持有) .<name>.step.generation.progress.json 状态记录(进度 JSON)

两个哨兵文件是刻意为之:构建要"重写整个包",而导出(STL/GLB 等)只占用生成器、写到别处。读者由此能区分**"模型正在被重写"(必须隐藏磁盘上的旧产物)和"生成器忙"**(旧产物仍可用)。

内核托管的 flock 锁:为什么放弃心跳状态文件?

coordination/lock.py 的模块头注释,几乎就是一份"事故复盘"。早期版本用{pid, status, startedAt}JSON 状态文件 + 1 秒心跳线程判断"构建是否存活",结果暴露了三个致命缺陷:

缺陷后果
状态文件只被写入、从未被"获取"两个并发构建各自放行,先完成的一方删掉共享文件时另一个还在写——读者在半成品上看到"无构建中"
os.kill(pid, 0)+ 30 秒心跳窗口推断存活网格化长时间持有 GIL,心跳线程饿死,健康构建被误判为已死
生产端从不互相等待,只有 Viewer 等待并发写入直接竞争同一目录

新设计只有一条铁律:锁状态归内核所有——进程崩溃或被 kill 时,内核随文件描述符关闭自动释放锁。代码里明确写着"No liveness inference lives here, and none may be added":不做 pid 检查、不做心跳、不做时间窗推断。

还有一个精巧的细节:读侧探测用共享锁LOCK_SH、写侧用排他锁LOCK_EX。因为flock是按打开文件描述计冲突而非按进程,若两个读者都用LOCK_EX探测,会彼此误报"有构建在飞"——修复前 4 线程并发下实测约 6% 的误报率。

锁等待与超时:--lock-timeout的设计取舍

CLI 的并发策略在 _internal/cli_locking.py 中:

  • 默认无限等待WAIT_FOREVER = 0.0):Agent 发起构建就是要产物,直接放弃只会留下"没构建、也没办法"的空手结果,排队等待才是正解
  • Viewer 必须不阻塞:它作为常驻服务显式传入超时,超时后不抛错,而是返回{"ok": true, "contended": true}——"没错,只是模型正在被别处构建"

等待期间还有一个体感设计:on_wait回调在等待超过 0.25 秒后首次播报、之后每 30 秒重复一次waiting for another run to finish building ...。没有它,一个排队中的构建在两个流上都不输出任何内容,和"进程挂死"完全无法区分(见 lock.py 的 _acquire)。

💡 使用层面:SKILL.md 里写得很直白——构建会等待同一模型的并发构建,并持续在 stderr 播报;加--lock-timeout SECONDS可改为放弃等待,此时该目标的 outcome 是contended,而不是built(参见 skills/cad/SKILL.md)。

旧进程残留的进度条:runId 归属机制

崩溃的构建会留下一份"非终态"的状态记录在磁盘上。如果没有识别手段,Viewer 会把一具"尸体的进度"渲染成当前构建的位置——比如显示"Meshing components 31/50",而当前构建其实一个组件都没网格化。

解法在 coordination/record.py:拿到锁时先在哨兵里盖上本次运行的 runId(UUID),读者只渲染 runId 与当前持锁者一致的状态记录。归属不匹配、schema 版本不认识、记录已终态——一律显示"无进度",安全降级。

写入侧同样是原子的:临时文件名带 pid 防多进程互踩,再os.replace落盘,轮询读者永远不会读到半截 JSON。

优雅降级:锁不可用,构建也绝不能失败

这套机制有一条贯穿始终的底线策略——"a build must never fail because a lock was unavailable"

  • fcntl/msvcrt、目录不可写、NFS/SMB 等不支持咨询锁的文件系统,统统降级为"无协调",照常构建
  • 状态记录写不进去?降级为"无进度上报",绝不因此失败
  • 在 Windows 的msvcrt区域锁上,空哨兵无法加锁(越过 EOF 加锁是错误),于是一个"open 后、写 runId 前崩溃"的空哨兵被报告为降级而非"被持有",避免永久卡死后续所有构建
  • 文件重命名在 SMB 上的共享冲突(WinError 32)由 atomic_replace.py 做 350ms 内的有界重试,但权限类错误立即上报——重试只留给"服务器还没跟上"这一种情况

值得借鉴的三个设计思想

  1. 权威来源唯一:谁活着,只问内核;状态文件只是"装饰",永远不承担存活判断
  2. 等待是默认,放弃是显式选择:把"排队"作为生产端默认语义,把"超时放弃"留给必须不阻塞的调用方
  3. 失败模式先于功能设计:每个环节(探测、加锁、写记录、重命名)都先回答"如果这里不可用,构建是否还能成功"

📁 想深入源码,核心路径:

  • 锁原语:coordination/lock.py
  • 文件布局:coordination/paths.py
  • 状态记录:coordination/record.py
  • CLI 超时与等待播报:_internal/cli_locking.py
  • 原子替换:_internal/atomic_replace.py

【免费下载链接】text-to-cadA library of agent skills for CAD, CAE and CAM项目地址: https://gitcode.com/GitHub_Trending/tex/text-to-cad

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

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

OpenXCAP not yet configured?TaoToken 这样给 Codex 换通道再排查

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

作者头像 李华
网站建设 2026/9/16 20:49:53

COMSOL仿真实现光子晶体BIC本征态计算

1. 项目背景与核心价值在光子晶体和超材料研究领域&#xff0c;连续谱束缚态&#xff08;Bound states in the continuum&#xff0c;简称BIC&#xff09;因其独特的非辐射特性和高品质因数&#xff0c;近年来成为光学器件设计的热点课题。传统计算方法往往面临模式识别困难、计…

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

SGVision零基础入门:图形化机器视觉实战指南

1. 为什么SGVision是零基础入门机器视觉的“隐形捷径”你有没有试过打开OpenCV文档&#xff0c;看到cv2.findContours()参数列表里密密麻麻的flag、mode、hierarchy就下意识关掉网页&#xff1f;或者在PyTorch官网翻到torch.nn.Conv2d那一长串初始化参数时&#xff0c;手指悬在…

作者头像 李华