C++实现Java风格对象锁:基于RAII的Synchronized模板类设计
1. 项目概述从Java的便捷到C的灵活在Java世界里synchronized关键字是每个开发者接触线程安全时最早遇到的老朋友。它简单、直接往方法或代码块上一贴就能保证同一时刻只有一个线程能执行这段代码锁的获取和释放由JVM自动管理开发者几乎不用操心。这种“语法糖”级别的便利性让很多从Java转向C的开发者感到不适应——C标准库并没有提供这样一个现成的、与对象生命周期绑定的互斥机制。这个项目的核心就是要在C中模拟实现Javasynchronized关键字那种“对象锁”的语义和便捷性。我们称之为“2.0版本”意味着它不仅仅是简单包装一个std::mutex而是要更深入、更安全、更贴合C RAII资源获取即初始化哲学同时规避一些初版设计中常见的陷阱。想象一下在C中也能写出类似void synchronized_method() { /* 临界区 */ }这样简洁且线程安全的代码或者为任意对象动态附加锁能力这正是本项目要达成的目标。它适合所有正在或即将使用C进行多线程开发的工程师无论是处理高并发服务器、游戏引擎还是需要线程安全的桌面应用掌握一种优雅的锁封装技术都能让你的代码更健壮、更易维护。2. 核心设计思路与方案选型直接使用std::mutex并手动调用lock()和unlock()是最基础的线程同步方法但这种方式极易出错。忘记解锁会导致死锁异常抛出时无法解锁同样会导致死锁。因此我们的设计必须围绕RAII展开确保锁的释放与对象作用域绑定。2.1 为何选择组合而非继承std::mutex的不可复制性第一个关键决策是如何将锁与目标对象关联一个直观的想法是让目标类继承自一个包含std::mutex的基类。但这里有一个致命问题std::mutex是不可拷贝且不可移动的。如果一个类继承了包含std::mutex的基类那么这个派生类也将默认是不可拷贝、不可移动的除非你显式地定义或删除这些特殊成员函数。这极大地限制了类的使用灵活性。因此更优的方案是使用组合Composition。我们将锁作为目标类的一个成员变量。这样目标类拷贝或移动的语义可以由开发者自行决定例如在拷贝构造函数中我们通常选择不拷贝互斥锁的状态而是初始化一个新的锁。这给了我们更大的控制权。2.2 锁管理器的设计分离关注点如果每个需要线程安全的类都自己包含一个std::mutex代码会显得重复且锁的管理逻辑分散在各处。我们引入一个“锁管理器”Synchronized的概念。这个管理器是一个模板类它持有两个东西被保护的数据对象T。用于保护该数据的互斥锁std::mutex。管理器的核心职责是提供一种安全的方式来访问被保护的数据。访问的唯一途径是通过管理器提供的方法这些方法会在访问期间自动加锁。这完美践行了RAII原则。2.3 访问模式仿Java的synchronized块Java的synchronized(obj)锁住的是对象监视器monitor。在我们的C实现中我们希望达到类似效果锁住与某个数据关联的互斥锁然后执行一段代码。我们可以通过让管理器提供一种“访问器”Accessor或Guard对象来实现。用户获取这个访问器时自动加锁访问器对象则提供了指向被保护数据的指针或引用。当访问器对象析构时锁自动释放。这样用户代码的临界区就由访问器对象的作用域来界定和Java的synchronized块异曲同工。3. 核心组件实现详解下面我们一步步拆解这个“对象锁2.0”的实现。我们将实现一个名为SynchronizedT的模板类。3.1SynchronizedT基础骨架与数据成员首先定义模板类它包含被保护的数据和互斥锁。我们使用std::mutex作为锁使用std::lock_guard或std::unique_lock作为RAII锁守卫。这里选择std::unique_lock是为了未来可能的扩展如条件变量。#include mutex #include type_traits templatetypename T class Synchronized { private: // 被保护的实际数据 mutable T data_; // 用于保护数据的互斥锁mutable使得在const成员函数中也能加锁 mutable std::mutex mutex_; public: // 构造函数完美转发所有参数以构造 data_ templatetypename... Args explicit Synchronized(Args... args) : data_(std::forwardArgs(args)...) { } // 禁止拷贝和赋值因为锁的复制语义不明确 Synchronized(const Synchronized) delete; Synchronized operator(const Synchronized) delete; // 允许移动可选根据需求 Synchronized(Synchronized) default; Synchronized operator(Synchronized) default; };注意mutex_和data_都被声明为mutable。这是因为我们期望Synchronized的const成员函数如只读访问也能进行线程安全的操作而加锁操作会改变mutex_的内部状态所以需要mutable。这是一种常见的、被认可的做法。3.2 锁守卫与访问器LockedPtr这是实现自动加解锁的核心。我们定义一个嵌套的代理类LockedPtr它在构造时加锁析构时解锁并重载了operator-和operator*以提供对数据的访问。templatetypename T class Synchronized { // ... 其他成员 ... public: // 前向声明 class LockedPtr; // 获取锁并返回访问器 LockedPtr lock() { return LockedPtr(*this); } // const 版本的获取锁 LockedPtr lock() const { return LockedPtr(*this); } // 锁守卫/访问器类 class LockedPtr { private: const Synchronized* parent_; std::unique_lockstd::mutex guard_; public: explicit LockedPtr(const Synchronized parent) : parent_(parent) , guard_(parent.mutex_) { // 构造时加锁 } // 提供指针语义访问被保护数据 T* operator-() { return parent_-data_; } const T* operator-() const { return parent_-data_; } // 提供引用语义访问被保护数据 T operator*() { return parent_-data_; } const T operator*() const { return parent_-data_; } // 析构时guard_自动释放锁 }; };使用方式对比Java风格synchronized(obj) { obj.doSomething(); }我们的C实现Synchronizedstd::vectorint syncVec; { auto locked syncVec.lock(); // 进入“同步块” 加锁 locked-push_back(42); // 安全地访问 vector (*locked).clear(); } // locked 析构自动解锁可以看到大括号{}定义了临界区的作用域与Java的synchronized块完全对应。3.3 便捷方法execute函数模板虽然LockedPtr已经很直观但我们还可以提供一种更函数式的接口让代码更紧凑。execute方法接受一个可调用对象函数、lambda表达式在锁的保护下执行它并传入数据的引用。templatetypename T class Synchronized { // ... 其他成员 ... public: templatetypename Func auto execute(Func func) - decltype(func(data_)) { std::lock_guardstd::mutex lock(mutex_); return func(data_); } templatetypename Func auto execute(Func func) const - decltype(func(data_)) { std::lock_guardstd::mutex lock(mutex_); return func(data_); } };使用示例Synchronizedstd::mapint, std::string syncMap; syncMap.execute([](auto map) { // 自动加锁map是 syncMap.data_ 的引用 map[1] Hello; map[2] World; }); int size syncMap.execute([](const auto map) { // const版本只读访问 return map.size(); });这种方式特别适合进行一系列连贯操作避免了手动管理LockedPtr对象代码更内聚。4. 高级特性与优化实现基础版本已经可用但一个健壮的“2.0”版本还需要考虑更多边界情况和性能优化。4.1 支持try_lock与非阻塞操作有时我们不想阻塞等待锁。我们可以为LockedPtr添加一个尝试锁定的构造函数并提供一个bool转换运算符或owns_lock()方法来检查是否成功获锁。class LockedPtr { private: // ... 其他成员 ... bool owns_lock_; public: // 尝试锁定的构造函数 explicit LockedPtr(const Synchronized parent, std::try_to_lock_t tag) : parent_(parent) , guard_(parent.mutex_, tag) , owns_lock_(guard_.owns_lock()) { } // 检查是否持有锁 explicit operator bool() const noexcept { return owns_lock_; } bool owns_lock() const noexcept { return owns_lock_; } }; // 在 Synchronized 类中添加 tryLock 方法 LockedPtr tryLock() { return LockedPtr(*this, std::try_to_lock); }使用场景if (auto locked syncObj.tryLock()) { // 成功获取锁执行操作 locked-doSomething(); } else { // 获取锁失败执行其他逻辑如记录日志、返回错误码 std::cout Object is busy, skipping operation.\n; }4.2 递归锁Recursive Mutex支持Java的synchronized方法是可重入的reentrant即同一个线程可以多次进入同一对象的同步块。标准的std::mutex是不可重入的重复加锁会导致死锁。为了模拟这一行为我们可以将内部的std::mutex替换为std::recursive_mutex。templatetypename T, typename MutexType std::recursive_mutex class Synchronized { private: mutable T data_; mutable MutexType mutex_; // ... 其余实现保持不变只需将 std::mutex 替换为 MutexType ... };通过模板参数我们可以灵活选择使用普通互斥锁还是递归锁。默认使用递归锁更贴近Java的行为但要注意递归锁通常性能稍差且可能掩盖糟糕的设计如过长的调用链持有锁。实操心得除非你明确需要模拟Java的可重入行为或者处理复杂的回调场景否则优先使用std::mutex。滥用递归锁会让锁的持有期变得不清晰增加调试难度。将MutexType作为模板参数为后续可能替换为更高效的锁如自旋锁std::spinlockC20起在semaphore中留出了可能性。4.3 死锁预防锁顺序与std::lock当需要同时锁住多个Synchronized对象时不固定的加锁顺序可能导致死锁。解决方案是使用标准库的std::lock或std::scoped_lockC17它可以一次性锁定多个互斥量且保证不会死锁。我们的LockedPtr设计使得直接使用std::lock变得困难。一种更实用的模式是提供一种“手动”锁定多个对象并获取其访问器的机制但这会破坏RAII的简洁性。更常见的做法是在需要锁定多个对象的场景下退一步思考设计看能否通过合并数据、使用分层锁或事务内存等方式避免。如果必须锁定多个建议在更高层的业务逻辑中使用std::unique_lock配合std::lock或std::scoped_lock来手动管理这些Synchronized对象内部的mutex_。示例需要小心使用SynchronizedDataA syncA; SynchronizedDataB syncB; std::unique_lock lockA(syncA.mutex_, std::defer_lock); std::unique_lock lockB(syncB.mutex_, std::defer_lock); std::lock(lockA, lockB); // 一次性无死锁地锁定两个锁 // 现在可以安全地操作 syncA.data_ 和 syncB.data_ // 但注意这绕过了Synchronized的接口直接操作了内部数据需确保线程安全。5. 典型应用场景与代码示例让我们通过几个具体场景来看看Synchronized如何简化代码。5.1 场景一线程安全的计数器与容器这是最常见的用例。#include iostream #include thread #include vector #include “Synchronized.h” // 假设我们的实现在此头文件中 Synchronizedint counter(0); Synchronizedstd::vectorstd::string logBuffer; void worker(int id) { for (int i 0; i 1000; i) { // 使用 execute 方法安全地递增计数器 counter.execute([id](int c) { c; // 模拟一些操作 }); // 使用 LockedPtr 安全地添加日志 auto lockedLog logBuffer.lock(); lockedLog-push_back(“Thread “ std::to_string(id) “ incremented count”); } } int main() { std::vectorstd::thread threads; for (int i 0; i 10; i) { threads.emplace_back(worker, i); } for (auto t : threads) { t.join(); } int finalCount counter.execute([](const int c) { return c; }); std::cout “Final counter value: “ finalCount std::endl; // 应为 10000 std::cout “Log entries: “ logBuffer.execute([](const auto vec) { return vec.size(); }) std::endl; return 0; }5.2 场景二封装复杂对象的状态同步假设我们有一个表示银行账户的类。class BankAccount { double balance_; public: BankAccount(double initial) : balance_(initial) {} void deposit(double amount) { balance_ amount; } bool withdraw(double amount) { if (balance_ amount) { balance_ - amount; return true; } return false; } double getBalance() const { return balance_; } }; // 使用 Synchronized 包装立刻获得线程安全的账户 SynchronizedBankAccount safeAccount(1000.0); // 线程安全的存款操作 void depositToAccount(double money) { safeAccount.execute([money](BankAccount acc) { acc.deposit(money); std::cout “Deposited “ money “, new balance: “ acc.getBalance() std::endl; }); } // 线程安全的取款操作 bool withdrawFromAccount(double money) { return safeAccount.execute([money](BankAccount acc) - bool { bool success acc.withdraw(money); if (success) { std::cout “Withdrew “ money “, new balance: “ acc.getBalance() std::endl; } else { std::cout “Failed to withdraw “ money “, insufficient funds.” std::endl; } return success; }); }6. 常见问题、陷阱与排查技巧即使有了Synchronized这样的封装多线程编程依然充满挑战。以下是一些实战中容易遇到的问题和解决思路。6.1 锁粒度与性能瓶颈问题将整个复杂对象用一个锁保护可能导致锁的持有时间过长成为性能瓶颈锁竞争激烈。例如一个线程在操作Synchronizedstd::map的某个元素时进行耗时计算其他所有线程都无法访问这个map。排查与解决性能分析使用性能剖析工具如perf, VTune查找热点看是否大量时间花费在锁等待上。细化锁粒度不要用一个大锁保护所有数据。考虑将数据拆分用多个Synchronized实例保护不同的部分。例如可以将map按key的哈希值分片sharding每个分片有自己的锁。缩短临界区在execute或LockedPtr作用域内只做必要的共享数据操作将任何可能的耗时计算如字符串格式化、磁盘I/O、复杂算法移到锁外执行。// 不佳做法在锁内进行格式化 syncData.execute([](auto data){ std::string logMsg verySlowFormatFunction(data); // 耗时 globalLog.push_back(logMsg); }); // 改进做法先拷贝数据出锁后再处理 Data copy; { auto locked syncData.lock(); copy *locked; // 假设Data可拷贝 } // 锁在这里就释放了 std::string logMsg verySlowFormatFunction(copy); // 在锁外执行耗时操作 globalLog.push_back(logMsg);6.2 回调与锁的传递问题在临界区内调用一个未知的函数如回调、虚函数该函数可能试图获取另一个锁导致锁顺序问题或死锁或者它可能重新进入当前锁如果是递归锁导致逻辑复杂化。排查与解决最小化临界区这是黄金法则。确保在持有锁时调用的函数是简单的、已知的、不会再去获取其他锁的。文档与约定如果设计上允许在锁内调用某些回调必须在文档中明确说明调用方Synchronized的使用者需要保证回调函数是“锁安全”的。避免在锁内调用用户代码如果可能将需要回调的数据从共享数据中提取出来在释放锁后再进行回调。6.3const正确性与线程安全问题我们使用了mutable mutex_来允许const成员函数加锁。但这带来了一个设计问题一个标记为const的Synchronized::execute操作虽然承诺不修改Synchronized对象本身即不改变mutex_和data_的地址等但它通过非常量引用将内部的data_暴露给了用户提供的函数func。用户可能在const操作中修改了数据。排查与解决严格接口Synchronized的const版本的execute和lock应该只接受接受const T或const T*的可调用对象/返回const访问器。这需要更精细的模板技巧例如使用std::enable_if或C20的requires来区分常量性。当前实现的妥协我们当前的简单实现其const版本在逻辑上并不保证数据的不可变性它只保证Synchronized对象本身的物理常量性。使用者需要自觉遵守约定通过const Synchronized对象获取的LockedPtr只应进行只读操作。编译器无法强制这一点这是一个设计上的权衡。6.4 调试与死锁检测问题复杂的锁交互导致死锁难以复现和定位。排查技巧代码审查仔细检查所有锁的获取顺序确保全局固定的顺序。使用工具Helgrind (Valgrind)一个强大的线程错误检测工具可以检测数据竞争、锁顺序问题等。Clang ThreadSanitizer (TSAN)在编译时添加-fsanitizethread标志可以在运行时检测数据竞争和死锁。自定义锁包装可以创建一个调试版本的DebugMutex继承自std::mutex但在lock()和unlock()时记录线程ID、时间戳和调用栈信息。当死锁发生时分析这些日志。日志记录在获取和释放锁时输出详细的日志包括线程ID和锁的地址或标识。虽然影响性能但在调试阶段非常有用。6.5 与标准库及其他同步原语的协作问题Synchronized内部使用了std::mutex如何与std::condition_variable一起使用以实现等待/通知机制解决方案std::condition_variable需要与一个std::unique_lockstd::mutex配合使用。我们的LockedPtr内部正好有一个std::unique_lock。我们可以通过给LockedPtr增加一个方法来暴露这个内部的unique_lock引用以便和条件变量配合。但这样做会破坏封装。更清晰的做法是将条件变量也作为被保护数据的一部分或者让Synchronized提供专门的wait/notify接口。示例将条件变量作为数据一部分struct SharedData { std::queueTask taskQueue; std::condition_variable cv; bool shutdown false; }; SynchronizedSharedData syncData; // 生产者线程 syncData.execute([](SharedData d){ d.taskQueue.push(newTask); d.cv.notify_one(); // 通知一个等待的消费者 }); // 消费者线程 std::unique_lockstd::mutex lock(syncData.mutex_); // 直接操作内部mutex需谨慎 syncData.data_.cv.wait(lock, [syncData]{ auto locked syncData.lock(); // 错误试图在已持有锁的线程上再次加锁除非是递归锁 return !syncData.data_.taskQueue.empty() || syncData.data_.shutdown; }); // 更好的模式是设计一个专门的 SynchronizedWithCV 模板类。最后我个人在实际项目中使用此类封装的经验是它极大地减少了因忘记解锁而导致的死锁让代码清晰度上了一个台阶。但它不是银弹锁粒度设计、避免在锁内执行耗时操作、以及处理好与条件变量等高级同步原语的关系仍然需要开发者仔细考量。将这个Synchronized模板类作为你线程安全工具箱中的一件利器在合适的场景下使用能让你编写出既安全又优雅的C并发代码。

相关新闻

网盘直链下载助手:告别限速困扰的浏览器下载神器

网盘直链下载助手:告别限速困扰的浏览器下载神器

网盘直链下载助手:告别限速困扰的浏览器下载神器 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 …

2026/10/18 4:02:50 阅读更多 →
TPS65735评估板实战指南:从电源管理到H桥驱动的完整测试与调试

TPS65735评估板实战指南:从电源管理到H桥驱动的完整测试与调试

1. 评估板开箱与核心功能初探刚拿到TPS65735EVM-703评估板的时候,第一感觉是德州仪器(TI)的做工确实扎实。这块板子不大,但麻雀虽小五脏俱全,它围绕TPS65735这颗单芯片电源管理单元(PMU)搭建&am…

2026/10/18 9:17:36 阅读更多 →
UCD90320电源序列器GPI配置与故障响应机制详解

UCD90320电源序列器GPI配置与故障响应机制详解

1. 项目概述与核心价值在复杂的多轨电源系统设计中,工程师经常面临一个核心挑战:如何让电源序列器智能地“感知”外部世界,并根据这些感知做出快速、准确的决策。例如,一个来自温度传感器的过热信号、一个来自处理器的“紧急关机”…

2026/10/18 9:36:07 阅读更多 →

最新新闻

3块钱2小时从零训练大模型:消费级显卡也能跑通GPT全流程

3块钱2小时从零训练大模型:消费级显卡也能跑通GPT全流程

最近朋友圈又被一个标题刷屏了:“3块钱,2小时,他用一张显卡从零训练了一个大模型”。说实话,这种标题搁以前我都是直接划走的,因为见过太多拿开源权重微调一下就叫“训练大模型”的玩法。但这次我决定亲手验证一把&…

2026/10/19 4:31:47 阅读更多 →
数据链路层期末复习指南:从帧定界到滑动窗口的核心考点解析

数据链路层期末复习指南:从帧定界到滑动窗口的核心考点解析

1. 数据链路层到底在解决什么问题1.1 从“两台机器怎么说话”说起学计算机网络,到了第三章数据链路层,很多人会突然觉得画风变了。前面物理层讲的还是电压、接口、比特流,到了这里,谢希仁老师的教材开始讲帧、差错控制、流量控制、…

2026/10/19 4:31:47 阅读更多 →
语言切成英文,下拉刷新还写着中文:HarmonyOS 7 SwipeRefresherV2 ResourceStr 与并发收口实战

语言切成英文,下拉刷新还写着中文:HarmonyOS 7 SwipeRefresherV2 ResourceStr 与并发收口实战

语言切成英文,下拉刷新还写着中文:HarmonyOS 7 SwipeRefresherV2 ResourceStr 与并发收口实战 系统语言已经切成英文,菜谱列表、按钮和空状态都变了,只有下拉刷新区域仍然显示“正在加载中”。另一台小屏设备上,把中文…

2026/10/19 4:31:47 阅读更多 →
Python+Vue构建物联网仓储进销存可视化系统:从库存准确率到大屏落地

Python+Vue构建物联网仓储进销存可视化系统:从库存准确率到大屏落地

去年我接了一个很典型的项目:某仓储企业想上一套基于 Python 和 Vue 的物联网仓储仓库进销存管理系统可视化。刚听完需求,我以为就是把进销存模块和几个大屏图表拼在一起,结果真正落地才发现,这里面有两个很难缠的问题——库存账目…

2026/10/19 4:31:47 阅读更多 →
手写签名识别实战:OpenCV传统图像处理实现轻量级笔迹判别

手写签名识别实战:OpenCV传统图像处理实现轻量级笔迹判别

简介:本资源是一套基于Python与OpenCV实现的笔迹识别系统完整项目源码,面向计算机视觉初学者、图像处理课程学习者及人工智能实践者,解决手写笔迹图像预处理、特征提取与分类识别等核心问题,适用于课程设计、大作业实践与算法入门…

2026/10/19 4:31:46 阅读更多 →
PyTorch实战:猫狗图像分类从入门到部署

PyTorch实战:猫狗图像分类从入门到部署

1. 为什么猫狗分类是入门深度学习的“试金石”如果你刚接触深度学习,想找一个既能跑通完整流程、又不会一上来就被复杂工程劝退的项目,猫狗图像分类几乎是公认的最佳起点。它不像手写数字识别那样过于简单,也不像目标检测或图像分割那样涉及大…

2026/10/19 4:30:46 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

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

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/18 12:16:16 阅读更多 →