我有一个从全局范围经常调用的第三方回调函数,为了同步我的缓冲区序列,我使用pthread_mutex_lock和PTHREAD_MUTEX_ERRORCHECK类型
所需的行为是每次对回调函数的调用都被阻止,直到处理完成之前的调用。我正在使用的互斥锁类型是否适用于此,因为我目前正在经历一个奇怪的系统锁定,完全冻结操作并怀疑我处理锁定错误后的代码导致了这种情况。按照设计,锁定永远不会失败。
答案 0 :(得分:0)
您的描述不是很清楚。通常不会从“全局范围”调用事物,只有某些类型的构造函数和析构函数。也许您所说的是外部函数调用:回调由另一个软件组件中的某些外部上下文调用。您也不清楚谁在编写回调。这是第三方库调用您的注册回调吗? “第三方回调”将是第三方库中的一个功能,它将自己注册为对您的回调。
我将假设您正在调用某个第三方库,它会调用您的回调,并且您在代码或第三方中遇到了死锁情况。
如果第三方代码中发生了死锁,那么您可能没有遵守回调可能会或可能不会执行的正确规则。您是否在回调中调用第三方代码?也许你不被允许这样做,或者不允许你这样做。也许第三方库在调用你的回调时持有一个互斥锁,你从该回调中调用的函数试图获取相同的互斥锁。
如果死锁在您自己的代码中,在您自己的互斥锁上,也许您正在做一些愚蠢的事情,比如拿着互斥锁,调用第三方代码然后再次尝试锁定互斥锁。如果它就这么简单,有各种方法。一个是在调用外部组件时永远不会持有互斥锁(这通常是个好主意,因为互斥锁应该保持很短的时间以避免争用)。在离开代码的路上释放一个互斥锁并在进入的路上重新获取它。有时这很不方便,因为无论何时释放互斥锁,“世界都会发生变化”,你必须重新检查受保护变量的状态并处理可能发生的情况。错误可能会蔓延,因此您的代码依赖于之前持有互斥量的假设,因为它释放了互斥锁,因此它不再适用。
可以使用此回调情况的另一种方法是回调假设 互斥锁已经被保持,并且不会将其锁定两次。如果回调是一些用作非回调的通用函数,则将其拆分为非锁定版本和锁定版本。将回调绑定到非锁定回调。
另一个可能导致死锁的事情是以相反的顺序获取多个锁。当线程以不同的顺序遍历大型程序的对象层次结构时,这很容易发生。例如。一些线程与Object A一起工作,它调用对象B上的方法,另一个线程正在做一些从B到A的事情。当你离开模块时总是释放锁的技术将有助于防止这种情况。在您无法做到这一点的情况下,您可以重构代码,以便始终以相同的顺序获取锁。
另一种工具是不同种类的锁。递归锁可以帮助(虽然它们是一个kludge)。在某些情况下,读写锁可以提供帮助。 “无锁”算法(使用原子机器指令形式的微型互斥体而不是大型OS互斥体)。