C++14似乎遗漏了一种检查std::mutex是否被锁定的机制。请看这个问题:
https://stackoverflow.com/questions/21892934/how-to-assert-if-a-stdmutex-is-locked
有几种方法可以解决这一问题,例如通过使用;
std::mutex::try_lock()
std::unique_lock::owns_lock()但这两种方法都不是特别令人满意的解决方案。
如果当前线程锁定了互斥对象,则允许try_lock()返回假否定,并且具有未定义的行为。它也有副作用。owns_lock()需要在原始std::mutex的基础上构造一个unique_lock。
显然,我可以使用自己的界面,但我更愿意理解当前界面的动机。
在我看来,检查互斥(例如std::mutex::is_locked())状态的能力似乎并不是一个深奥的请求,因此我怀疑标准委员会故意忽略了这个特性,而不是忽略它。
为什么?
编辑:好的,也许这个用例并不像我预期的那么常见,所以我将说明我的特定场景。我有一个机器学习算法,它分布在多个线程上。每个线程异步操作,并在完成优化问题后返回到主池。
然后它锁定一个主互斥体。然后,线程必须选择一个新的父级来突变后代,但只能从当前没有其他线程正在优化的子代的父母那里选择。因此,我需要执行一个搜索,以找到当前没有被另一个线程锁定的父母。由于主线程互斥锁被锁定,因此在搜索过程中不存在互斥锁状态更改的风险。显然还有其他解决方案(我目前使用的是布尔标志),但我认为互斥锁为这个问题提供了一个逻辑解决方案,因为它是为了线程间同步而存在的。
发布于 2016-09-11 14:22:13
我至少可以看出建议的手术有两个严重的问题。
@gnasher729的评论中已经提到了第一个:
您不能真正合理地检查一个互斥体是否被锁定,因为在检查之后的一纳秒,它可以被解锁或锁定。因此,如果您编写了
if (mutex_is_locked ()) …,那么mutex_is_locked可以返回正确的结果,但是在执行if时,它是错误的。
确保互斥锁的“当前锁定”属性不会更改的唯一方法是,嗯,自己锁定它。
我看到的第二个问题是,除非锁定互斥锁,否则线程不会与先前锁定互斥锁的线程同步。因此,谈论“前”和“后”,以及互斥锁不上锁,都是在问Schr diger的猫是否还活着,而不是试图打开盒子。
如果我正确理解,那么这两个问题在您的特殊情况下都是没有意义的,这要归功于主互斥锁。但在我看来,这似乎不是一个特别常见的情况,所以我认为,委员会做了正确的事情,没有添加一个功能,在非常特殊的情况下可能有些有用,并在所有其他情况下造成损害。(本着“使接口易于正确使用和难以正确使用”的精神。)
如果我可以说,我认为您目前的设置不是最优雅的,可以重构以避免问题。例如,与其在主线程中检查当前未锁定的所有潜在父线程,不如保持一个已准备好的父母队列?如果一个线程想要优化另一个线程,它将弹出队列中的下一个线程,并且一旦它有了新的父级,就会将它们添加到队列中。这样,您甚至不需要主线程作为协调器。
发布于 2016-09-11 18:27:42
似乎您使用次级互斥锁不是为了锁定对优化问题的访问,而是确定当前是否正在优化优化问题。
这完全没有必要。我会有一个需要优化的问题列表,一个正在优化的问题列表,以及一个已经优化的问题列表。(不要从字面上看“列表”,而是指“任何适当的数据结构”)。
在未优化的问题列表中添加一个新问题,或者将一个问题从一个列表转移到另一个列表的操作,将在单个“主”互斥体的保护下完成。
发布于 2016-09-11 16:34:39
除了在上面的答案中给出的两个理由之外,我还想补充一点,这既没有必要,也不可取。
如果你已经持有一个互斥,那么你最好知道你持有它!你不需要问。就像拥有一个内存块或任何其他资源一样,您应该确切地知道是否拥有它,以及何时适当地释放/删除该资源。
如果不是这样的话,你的程序设计得很糟糕,你就会遇到麻烦。
如果您需要访问由互斥体保护的共享资源,并且您还没有保存互斥锁,那么您需要获取互斥锁。没有其他选择,否则您的程序逻辑是不正确的。
您可能会发现阻塞是可以接受的或者是不可接受的,无论是lock()还是try_lock()都会给出您想要的行为。您需要知道的是,您是否成功地获得了互斥对象( try_lock的返回值告诉您)。它是无关紧要的,无论是其他人持有它,或你是否有一个虚假的失败。
在其他情况下,坦率地说,这不关你的事。您不需要知道,也不应该知道,或者做出假设(对于在另一个问题中提到的及时性和同步问题)。
https://softwareengineering.stackexchange.com/questions/330769
复制相似问题