ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C++17 scoped_lock:同时锁住多个互斥量,让锁的释放跟着作用域走

C++17 scoped_lock:同时锁住多个互斥量,让锁的释放跟着作用域走 C17 scoped_lock同时锁住多个互斥量让锁的释放跟着作用域走两个对象各有一把锁需要同时修改它们时最容易写出相反的加锁顺序。一个线程先锁 A 再锁 B另一个先锁 B 再锁 A就可能互相等待。最低标准C17。示例只演示内存中的库存数量转移不涉及外部系统。1. 把多把锁交给一个 RAII 对象#includeiostream#includemutex#includethreadstructBin{std::mutex mutex;intcount100;};booltransfer(Binfrom,Binto,intamount){if(fromto||amount0)returnfalse;std::scoped_lockguard(from.mutex,to.mutex);if(from.countamount)returnfalse;from.count-amount;to.countamount;returntrue;}intmain(){Bin a,b;std::threadfirst([]{transfer(a,b,10);});std::threadsecond([]{transfer(b,a,20);});first.join();second.join();std::couta.count b.count\n;}输出为 110 90。两次转移无论先后都满足库存条件且加起来的总量保持 200。主线程在 join 之后读取此时两个工作线程已经结束。2. scoped_lock 不只是省掉 unlock构造时获取锁析构时释放锁所以提前 return 或异常退出也不会遗漏解锁。传入多个互斥量时会采用避免死锁的多锁获取方式而不是简单照参数顺序逐把阻塞加锁。必须给锁对象起名字。只构造一个临时 scoped_lock它可能在当前语句结束时就析构后面的数据操作并没有受到保护。3. 同一个对象要在加锁前处理示例先检查 from to避免把同一个非递归 mutex 作为两把不同锁交进去。真实接口应明确“自己转给自己”是无操作、失败还是其他含义。同样不要在已经手动持有这些非递归锁时又调用会重新锁住它们的函数。死锁避免算法不能修复任意的重入错误。4. 多锁工具不等于整个程序无死锁如果其他路径持锁等待线程结束、调用未知回调、等待网络或使用不兼容的加锁协议仍可能形成更大的等待环。锁内部应尽量短不做未知耗时操作。scoped_lock 也不提供条件变量等待所需的灵活解锁接口这类场景通常使用 unique_lock。仅锁一把且不需要额外控制时lock_guard 也仍然合适。示例的整数范围很小。生产代码除了锁还需处理数值溢出、对象寿命以及所有读写路径是否遵守同一同步规则。锁解决并发访问不自动保证业务正确性。
返回列表