【发布时间】:2010-12-14 14:12:13
【问题描述】:
假设一个进程正在共享内存中创建一个互斥体并锁定它并在互斥体被锁定时转储核心。
现在在另一个进程中,我如何检测互斥锁已被锁定但不属于任何进程?
【问题讨论】:
标签: c++ c linux mutex shared-memory
假设一个进程正在共享内存中创建一个互斥体并锁定它并在互斥体被锁定时转储核心。
现在在另一个进程中,我如何检测互斥锁已被锁定但不属于任何进程?
【问题讨论】:
标签: c++ c linux mutex shared-memory
似乎已经以强大的互斥锁的形式提供了确切的答案。
根据 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
【讨论】:
如果您在 Linux 或类似的环境中工作,请考虑使用 named semaphores 而不是(我假设是)pthreads 互斥锁。我认为没有办法确定 pthreads 互斥锁的锁定 PID,除了建立自己的注册表并将其放入共享内存中。
【讨论】:
基于文件的锁定(使用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;
}
输出(为了清楚起见,我稍微截断了 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
发生的情况是第一个程序获得了锁并开始休眠 5 秒。 2 秒后,启动程序的第二个实例,该实例在尝试获取锁时阻塞。 3 秒后,第一个程序出现段错误(不过 bash 直到稍后才告诉你),然后第二个程序立即获得锁并继续。
【讨论】:
flock(2)。当您的进程终止时,文件将自动关闭,并且应该释放它的锁定。
只有当有人有相同的想法并且会发现这个关于使用的讨论时,我才会保留这个错误的帖子!
您可以使用这种方法。 1) 锁定 POSIX 共享互斥锁 2) 将 process-id 保存在共享内存中。 3) 解锁共享互斥锁 4) 在正确退出时清理进程 ID
如果进程 coredumps 下一个进程会发现在共享内存中有一个在第 2 步保存的进程 ID。如果操作系统中没有具有此进程 ID 的进程,则没有人拥有共享互斥锁。所以只需要替换process-id即可。
更新以回答评论:
场景 1: 1. P1开始 2. P1 创建/打开一个命名互斥体(如果它不存在) 3. P1 timed_locks 命名互斥体并成功完成(必要时等待 10 秒); 4. P1核心转储 5. P2 在 coredump 之后启动 6. P2创建/打开一个命名互斥体,存在,没关系 7. P2 timed_locks 命名互斥体,锁定失败(必要时等待10秒); 8. P2 移除命名互斥体 9. P2 重新创建一个命名互斥体并锁定它
【讨论】:
您应该使用操作系统提供的信号量。
操作系统释放进程已打开的所有资源,无论它是终止还是正常退出。
【讨论】: