如何恢复一个信号量的过程,减less到零崩溃?

我有多个使用g ++编译的应用程序,运行在Ubuntu中。 我正在使用命名的信号来协调不同的进程。

所有工作正常, 除了在以下情况:如果其中一个进程调用sem_wait()sem_timedwait()来减less信号量,然后死机或死亡-9之前有机会调用sem_post() ,那么从那一刻,这个指定的信号量是“不可用的”。

所谓“不可用”,我的意思是信号计数现在为零,本来应该增加到1的过程已经死亡或被杀死了。

我找不到一个sem_*() API,它可能会告诉我最后一次减less的进程崩溃。

我在哪里错过了一个API?

以下是我如何打开指定的信号量:

 sem_t *sem = sem_open( "/testing", O_CREAT | // create the semaphore if it does not already exist O_CLOEXEC , // close on execute S_IRWXU | // permissions: user S_IRWXG | // permissions: group S_IRWXO , // permissions: other 1 ); // initial value of the semaphore 

这是我如何递减:

 struct timespec timeout = { 0, 0 }; clock_gettime( CLOCK_REALTIME, &timeout ); timeout.tv_sec += 5; if ( sem_timedwait( sem, &timeout ) ) { throw "timeout while waiting for semaphore"; } 

原来没有办法可靠地恢复信号量。 当然,任何人都可以post_sem()到指定的信号量来让计数再次增加到零,但是如何知道何时需要这样的恢复呢? 所提供的API太有限,并没有以任何方式表明发生这种情况。

当心ipc工具也可用 – 通用工具ipcmkipcrmipcs仅适用于过时的SysV信号量。 他们特别不使用新的POSIX信号量。

但是看起来还有其他的东西可以用来locking事物,当一个应用程序以无法被信号处理器捕获的方式死掉时,操作系统会自动释放这些东西。 两个示例:绑定到特定端口的侦听套接字,或特定文件上的locking。

我决定locking一个文件是我需要的解决scheme。 所以,而不是一个sem_wait()sem_post()调用,我使用:

 lockf( fd, F_LOCK, 0 ) 

 lockf( fd, F_ULOCK, 0 ) 

当应用程序以任何方式退出时,文件将自动closures,同时释放文件locking。 等待“信号量”的其他客户端应用程序可以按预期方式自由进行。

感谢您的帮助,伙计们。

使用锁文件而不是信号量,就像@Stéphane的解决scheme,但没有flock()调用。 你可以简单地使用独占锁来打开文件:

 //call to open() will block until it can obtain an exclusive lock on the file. errno = 0; int fd = open("/tmp/.lockfile", O_CREAT | //create the file if it's not present. O_WRONLY | //only need write access for the internal locking semantics. O_EXLOCK, //use an exclusive lock when opening the file. S_IRUSR | S_IWUSR); //permissions on the file, 600 here. if (fd == -1) { perror("open() failed"); exit(EXIT_FAILURE); } printf("Entered critical section.\n); //Do "critical" stuff here. //exit the critical section errno = 0; if (close(fd) == -1) { perror("close() failed"); exit(EXIT_FAILURE); } printf("Exited critical section.\n"); 

pipe理信号量时,这是一个典型的问题。 某些程序使用单个进程来pipe理信号量的初始化/删除。 通常这个过程只是这个,没有别的。 您的其他应用程序可以等到信号量可用。 我已经看到这与SYSVtypes的API完成,但不是与POSIX。 类似于“ 鸭子 ”提到的,在semop()调用中使用SEM_UNDO标志。

但是,根据您提供的信息,我build议您不要使用信号量。 特别是如果你的过程有被杀死或崩溃的危险。 尝试使用操作系统将自动为您清理的东西。

你应该能够使用lsof从shell中find它。 那么可能你可以删除它?

更新

啊是的… man -k semaphore来拯救。

看来你可以使用ipcrm来摆脱信号量。 似乎你不是第一个这个问题。

你需要仔细检查,但我相信sem_post可以从信号处理程序调用。 如果你能够抓住一些正在推迟这个过程的情况,这可能会有所帮助。

与互斥体不同,任何进程或线程(具有权限)都可以发布到信号量。 你可以写一个简单的工具来重置它。 大概你知道你的系统何时陷入僵局。 您可以将其closures并运行实用程序。

另外semaphone通常列在/ dev / shm下,你可以删除它。

SysV信号量更适合这种情况。 你可以指定SEM_UNDO,在这个系统中,如果死亡,系统将会退出信号量的变化。 他们也有能力告诉你最后一个进程ID来改变信号量。

如果这个过程是KILLED,那么就没有任何直接的方法来确定它已经消失了。

您可以在所有信号量中进行某种周期性的完整性检查 – 使用semctl (cmd = GETPID)查找在描述的状态下触及每个信号量的最后一个进程的PID,然后检查该进程是否还在。 如果没有,请执行清理。

只需在sem_unlink()之后立即执行sem_open() 。 Linux将在所有进程closures资源(包括内部closures)后删除。