2009-11-09 40 views

回答

8

如果你在Linux或类似的东西,可考虑使用named semaphores而不是(我假设是什么)并行线程互斥。我不认为有一种方法可以确定pthreads互斥量的锁定PID,而不是构建自己的注册表并将其放入共享内存。

+4

一般同意信号量建议,但POSIX信号量并不真正解决问题,因为它们也不记录锁定过程的PID,也不会在不合时宜的死亡情况下解锁。虽然它们可能是SysV信号量,但生锈和笨拙的确会跟踪PID,并且可以在使用SEM_UNDO选项调用时恢复。 – Duck 2009-11-09 22:07:20

1

您应该使用操作系统提供的信号量。

操作系统释放进程已打开的所有资源,无论它是否死亡或正常退出。

+0

并非在所有资源。如果OP按照建议使用POSIX信号量,并且持有锁的进程死亡,则信号量的值不会恢复,从而可能使其他进程死锁。 – Duck 2009-11-09 19:37:13

1

只有当有人会有相同的想法并且会发现这个讨论的使用时,我才会退出这个错误的帖子!


您可以使用这种方法。 1)锁定POSIX共享互斥锁 2)将进程ID保存在共享内存中。 3)解锁共享互斥 4)在正确的出口清洁过程-ID

如果进程核心转储下一过程会发现,在共享存储器中有保存在步骤#2中的进程ID。如果在操作系统中没有这个进程ID的进程,那么没有人拥有共享互斥。所以只需要替换进程ID。为了回答评论

更新:

场景1:1。 开始P1 2. P1创建/打开一个名为互斥体,如果它不存在 3. P1它timed_locks命名的互斥体和successfuly (如果需要,等待10秒); 4. P1 coredumps 5. P2在coredump后启动 6. P2创建/打开一个已命名的互斥锁,它存在,它是OK 7. P2 timed_locks已命名的互斥锁并且无法锁定(如果需要,等待10秒); 8. P2删除命名的互斥体 9. P2再现了命名的互斥体&锁定

+0

我在这里没有看到解决方案。情况1:(1)P1锁; (2)P1死亡; (3)死锁。情景2:(1)P1锁; (2)P1写pid; (3)P1解锁; (4)P2得到控制并锁定并找到P1 pid。场景3:如果切换顺序以便在解锁和进程死亡之前清除pid,则可以回到最初的问题,即死进程持有锁并使其他进程死锁。我错过了什么吗? – Duck 2009-11-09 21:42:26

+0

评论场景#1 – 2009-11-10 16:13:31

+0

此更新无法使用。对任意时间的依赖是不好的。但更糟糕的是,如果超过1个进程试图执行这个公式,那么在删除,重新创建,锁定等互斥量的时候,所有地狱都可能崩溃。 – Duck 2009-11-10 21:12:37

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; 
} 

输出(我已经截断了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直到后来才告诉你),第二个程序获得锁定并继续。

+0

我不认为taht会被删除,因为无论是文件还是内存都是同样的东西。 – Vivek 2009-11-14 08:05:06

+0

我的意思不是通过在文件中写入某些东西(它确实是相似的),而是使用'flock(2)'。当你的进程死亡时,文件将被自动关闭,并且它的锁定应该被释放。 – Wim 2009-11-14 08:21:19

+0

+1只有flock(fileno(f),LOCK_EX | LOCK_NB)更安全 – dashesy 2012-05-03 17:04:40

30

似乎确切的答案已经以强健的互斥体的形式提供。

根据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

+3

我认为这是一个更好的答案。到目前为止,我一直在Solaris上使用强大的互斥锁。 – 2010-10-18 17:03:14

+2

强大的互斥体非常棒,但请注意,如果互斥体是在父进程中创建的,然后分叉和子进程同时持有互斥锁,它们可能无法在glibc 2.15之前的GNU/Linux上正常工作。 [bug](http://sourceware.org/bugzilla/show_bug.cgi?id=13002)在glibc 2.15中修复。如果共享互斥体的两个进程不是由分叉创建的父代和子代,那么即使使用旧的glibc版本,健壮的互斥体也可以正常工作。 – 2013-01-10 23:27:52