在多线程系统上,如果两个线程在锁定互斥锁后想要在共享内存上工作。
主题A:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
class Example(App):
def build(self):
self.root = FloatLayout()
self.label = Label(text="I'm centered :(", pos=(0,0), size_hint=(1.0,1.0), halign="left")
self.label.text_size = self.label.size #no horizontal change
self.root.add_widget(self.label)
return self.root
Example().run()
主题B:
pthread_mutex_lock(&mutex)
....... //Memory corruption or Assert and thread exits
pthread_mutex_unlock(&mutex)
如果线程A首先获取互斥锁并因内存损坏或断言而退出,则线程B将永远等待导致死锁。
答案 0 :(得分:1)
您可以在互斥锁上设置ROBUST
属性。使用强大的互斥锁,如果获取它的线程由于某种原因退出而不解锁它,则互斥锁进入一个特殊状态,其中尝试锁定它的下一个线程将获得EOWNERDEAD
。
然后该线程负责清除任何不一致的状态。如果可以恢复,则线程应在pthread_mutex_consistent(3)
之前的任何时间调用pthread_mutex_unlock(3)
,以便其他线程可以像以前一样使用它。如果无法恢复,则应在不调用pthread_mutex_consistent(3)
的情况下解锁互斥锁,导致它进入不可用状态,其中唯一允许的操作是销毁它。
请注意,即使返回EOWNERDEAD
,互斥锁也会被锁定(我认为这是pthread_mutex_lock(3)
返回错误但锁定互斥锁的唯一条件。)
要设置ROBUST
属性,请在初始化互斥锁属性实例后使用pthread_mutexattr_setrobust(3)
。请记住,必须在初始化互斥锁之前完成此操作。所以,像:
pthread_mutex_t mutex;
pthread_mutexattr_t mutex_attrs;
if (pthread_mutexattr_init(&mutex_attrs) != 0) {
/* Handle error... */
}
if (pthread_mutexattr_setrobust(&mutex_attrs, PTHREAD_MUTEX_ROBUST) != 0) {
/* Handle error... */
}
if (pthread_mutex_init(&mutex, &mutex_attrs) != 0) {
/* Handle error... */
}
然后你就可以使用它:
int lock_res = pthread_mutex_lock(&mutex);
if (lock_res == EOWNERDEAD) {
/* Someone died before unlocking the mutex
* We assume there's no cleanup to do
*/
if (pthread_mutex_consistent(&mutex) != 0) {
/* Handle error... */
}
} else if (lock_res != 0) {
/* Some other error, handle it here */
}
/* mutex is locked here, do stuff... */
if (pthread_mutex_unlock(&mutex) != 0) {
/* Handle error */
}
有关详细信息,请参阅pthread_mutex_consistent(3)和pthread_mutex_getrobust(3) / pthread_mutex_setrobust(3)
的联机帮助页答案 1 :(得分:0)
如果你想让线程自行清理,你通常需要自己要求或自己动手。
例如,您可以使用pthread_cleanup_push()
and pthread_cleanup_pop()
来确保在线程使用pthread_exit()
退出或者取消时(通过pthread_cancel()
)进行清理。
此API的缺点是每对调用必须位于相同的函数和相同的词法嵌套级别(例如,在您的线程的入口函数中)。
我无法判断您是否被允许从信号处理程序中取消线程,因此您可能无法使用该API处理此问题,并且这些类型的错误和断言通常会使整个过程退出(尽管可能是如果您正在实现自己的断言变体,则可以调用pthread_exit()
)。
当所有者死亡时,确实存在其他锁定类型会自动解锁(例如flock()
锁定,或强大的互斥锁,如FilipeGonçalves所示),但在有人丢失锁定的情况下,您几乎无法保证状态一致性并且需要在他们之后进行清理