如何摆脱 linux 中的僵局
How to come out of a deadlock in linux
在多线程系统上,如果两个线程在锁定互斥量后想在共享内存上工作。
线程 A:
pthread_mutex_lock(&mutex)
....... //Memory corruption or Assert and thread exits
pthread_mutex_unlock(&mutex)
线程 B:
pthread_mutex_lock(&mutex)
.......
pthread_mutex_unlock(&mutex)
如果线程A先获取到互斥量,然后由于内存损坏或断言而退出,线程B将永远等待导致死锁。
- 有没有 way/method 我可以用来摆脱这种僵局,一旦发生这种情况?
- 有没有其他类似互斥锁的更安全的方法可以使用?
如果你想让线程自己清理,一般需要自己提出或自己做。
例如,您可以使用 pthread_cleanup_push()
and pthread_cleanup_pop()
to ensure cleanup happens if the thread exits using pthread_exit()
or if it is cancelled (by way of pthread_cancel()
).
这个 API 的缺点是每对调用必须在同一个函数中,并且在同一个词法嵌套级别(例如,在你的线程的入口函数中)。
我不知道你是否被允许从信号处理程序中取消线程,所以你可能无法使用 API 来处理这个问题,这些类型的错误和断言通常会使整个进程退出(不过,大概如果您要实现自己的断言变体,它可能会调用 pthread_exit()
)。
确实存在其他锁类型,当所有者去世时会自动解锁(例如 flock()
锁,或 Filipe Gonçalves 展示的稳健互斥锁),但在有人丢失的情况下,您几乎无法保证状态一致性一把锁,需要在他们之后清理
您可以在互斥锁上设置 ROBUST
属性。使用健壮的互斥锁,如果获取它的线程由于某种原因退出而没有解锁它,互斥锁会进入一种特殊状态,在该状态下,下一个尝试锁定它的线程将获得 EOWNERDEAD
.
然后该线程负责清除任何不一致的状态。如果可以恢复,线程应在 pthread_mutex_unlock(3)
之前的任何时间调用 pthread_mutex_consistent(3)
,以便其他线程可以像以前一样使用它。如果无法恢复,则应在不调用 pthread_mutex_consistent(3)
的情况下解锁互斥体,使其进入无法使用的状态,唯一允许的操作是销毁它。
请注意,即使返回了 EOWNERDEAD
,互斥量也会被锁定(我认为这是 pthread_mutex_lock(3)
returns 出现错误但锁定互斥量的唯一条件)。
要设置 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) and pthread_mutex_getrobust(3) / pthread_mutex_setrobust(3)
的联机帮助页
在多线程系统上,如果两个线程在锁定互斥量后想在共享内存上工作。
线程 A:
pthread_mutex_lock(&mutex)
....... //Memory corruption or Assert and thread exits
pthread_mutex_unlock(&mutex)
线程 B:
pthread_mutex_lock(&mutex)
.......
pthread_mutex_unlock(&mutex)
如果线程A先获取到互斥量,然后由于内存损坏或断言而退出,线程B将永远等待导致死锁。
- 有没有 way/method 我可以用来摆脱这种僵局,一旦发生这种情况?
- 有没有其他类似互斥锁的更安全的方法可以使用?
如果你想让线程自己清理,一般需要自己提出或自己做。
例如,您可以使用 pthread_cleanup_push()
and pthread_cleanup_pop()
to ensure cleanup happens if the thread exits using pthread_exit()
or if it is cancelled (by way of pthread_cancel()
).
这个 API 的缺点是每对调用必须在同一个函数中,并且在同一个词法嵌套级别(例如,在你的线程的入口函数中)。
我不知道你是否被允许从信号处理程序中取消线程,所以你可能无法使用 API 来处理这个问题,这些类型的错误和断言通常会使整个进程退出(不过,大概如果您要实现自己的断言变体,它可能会调用 pthread_exit()
)。
确实存在其他锁类型,当所有者去世时会自动解锁(例如 flock()
锁,或 Filipe Gonçalves 展示的稳健互斥锁),但在有人丢失的情况下,您几乎无法保证状态一致性一把锁,需要在他们之后清理
您可以在互斥锁上设置 ROBUST
属性。使用健壮的互斥锁,如果获取它的线程由于某种原因退出而没有解锁它,互斥锁会进入一种特殊状态,在该状态下,下一个尝试锁定它的线程将获得 EOWNERDEAD
.
然后该线程负责清除任何不一致的状态。如果可以恢复,线程应在 pthread_mutex_unlock(3)
之前的任何时间调用 pthread_mutex_consistent(3)
,以便其他线程可以像以前一样使用它。如果无法恢复,则应在不调用 pthread_mutex_consistent(3)
的情况下解锁互斥体,使其进入无法使用的状态,唯一允许的操作是销毁它。
请注意,即使返回了 EOWNERDEAD
,互斥量也会被锁定(我认为这是 pthread_mutex_lock(3)
returns 出现错误但锁定互斥量的唯一条件)。
要设置 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) and pthread_mutex_getrobust(3) / pthread_mutex_setrobust(3)
的联机帮助页