如何摆脱 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将永远等待导致死锁。

  1. 有没有 way/method 我可以用来摆脱这种僵局,一旦发生这种情况?
  2. 有没有其他类似互斥锁的更安全的方法可以使用?

如果你想让线程自己清理,一般需要自己提出或自己做。

例如,您可以使用 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)

的联机帮助页