一个用户崩溃时共享内存中的互斥锁?

Viv*_*vek 15 c c++ linux mutex shared-memory

假设进程正在共享内存中创建互斥锁并锁定它并在互斥锁被锁定时转储核心.

现在在另一个过程中,如何检测互斥锁已被锁定但不属于任何进程?

Rob*_*sak 31

似乎确切的答案是以强大的互斥体的形式提供的.

根据POSIX,可以使用pthread_mutexattr_setrobust()初始化pthread互斥锁.如果持有互斥锁的进程随后死亡,则获取它的下一个线程将接收EOWNERDEAD(但仍然成功获取互斥锁),以便它知道执行任何清理.然后,它需要使用pthread_mutex_consistent()通知所获取的互斥锁再次一致.

显然你需要内核和libc支持才能工作.在Linux上,这背后的内核支持称为"健壮的futexes",我发现对glibc HEAD应用的用户空间更新的引用.

实际上,至少在Linux世界中,对此的支持似乎还没有过滤掉.如果这些函数不可用,你可能会在那里找到pthread_mutexattr_setrobust_np(),据我所知,它似乎是一个提供相同语义的非POSIX前身.我在Solaris文档和Debian上的/usr/include/pthread.h中都找到了对pthread_mutexattr_setrobust_np()的引用.

可在此处找到POSIX规范:http://www.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setrobust.html

  • 我认为这是一个更好的答案.到目前为止,我一直在Solaris上使用强大的互斥锁. (3认同)
  • 强大的互斥体很棒,但是请注意,如果互斥体是在父进程中创建的,那么它们可能无法在glibc 2.15之前在GNU/Linux上正常工作,而父进程然后分叉并且子进程在持有互斥锁时死亡.[bug](http://sourceware.org/bugzilla/show_bug.cgi?id=13002)已在glibc 2.15中修复.如果共享互斥锁的两个进程不是通过分叉创建的父进程和子进程,那么即使使用较旧的glibc版本,强健的互斥锁也能正常工作. (2认同)

Gen*_*man 9

如果你在Linux或类似的东西工作,考虑使用命名信号量而不是(我假设的)pthreads互斥量.我不认为有一种方法可以确定pthreads互斥锁的锁定PID,而不是构建自己的注册表并将它放在共享内存中.

  • 一般同意信号量建议,但POSIX信号量并没有真正解决问题,因为他们也没有记录锁定过程的PID,也没有在不合时宜的死亡时解锁.尽管它们可能是SysV信号量,但是生锈且笨拙的确实跟踪PID并且在使用SEM_UNDO选项调用时可以恢复. (4认同)

Wim*_*Wim 5

基于文件的锁定(使用flock(2))怎么样?当持有它的过程死亡时,它们会自动释放.

演示程序:

#include <stdio.h>
#include <time.h>
#include <sys/file.h>

void main() {
  FILE * f = fopen("testfile", "w+");

  printf("pid=%u time=%u Getting lock\n", getpid(), time(NULL));
  flock(fileno(f), LOCK_EX);
  printf("pid=%u time=%u Got lock\n", getpid(), time(NULL));

  sleep(5);
  printf("pid=%u time=%u Crashing\n", getpid(), time(NULL));
  *(int *)NULL = 1;
}
Run Code Online (Sandbox Code Playgroud)

输出(为了清楚起见,我已经截断了PID并稍微调整一下):

$ ./a.out & sleep 2 ; ./a.out 
[1] 15
pid=15 time=137 Getting lock
pid=15 time=137 Got lock
pid=17 time=139 Getting lock
pid=15 time=142 Crashing
pid=17 time=142 Got lock
pid=17 time=147 Crashing
[1]+  Segmentation fault      ./a.out
Segmentation fault
Run Code Online (Sandbox Code Playgroud)

会发生什么是第一个程序获得锁定并开始睡眠5秒钟.2秒后,程序的第二个实例启动,在尝试获取锁定时阻塞.3秒后,第一个程序段错误(bash直到稍后才告诉你)并且立即,第二个程序获得锁定并继续.