当递减到零的进程崩溃时,如何恢复信号量?

Sté*_*ane 47 linux gcc semaphore g++

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

一切正常,除非在以下情况下:如果其中一个进程调用sem_wait()sem_timedwait()减少信号量然后在它有机会调用之前崩溃或被杀死-9 sem_post(),那么从那一刻起,命名信号量就"无法使用".

通过"不可用",我的意思是信号量计数现在为零,并且应该将其增加回1的过程已经死亡或被杀死.

我找不到一个sem_*()API,可能会告诉我上次减少崩溃的过程.

我在某个地方错过了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
Run Code Online (Sandbox Code Playgroud)

这是我如何减少它:

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";
}
Run Code Online (Sandbox Code Playgroud)

Sté*_*ane 41

事实证明,没有办法可靠地恢复信号量.当然,任何人都可以post_sem()通过指定的信号量让计数再次增加到零,但是如何判断何时需要这样的恢复?提供的API太有限,并且在发生这种情况时不以任何方式表明.

的IPC工具也可当心-常用工具ipcmk,ipcrm以及ipcs只对过时的SysV信号灯.它们特别适用于新的POSIX信号量.

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

我决定锁定文件是我需要的解决方案.所以我没有使用sem_wait()sem_post()调用,而是使用:

lockf( fd, F_LOCK, 0 )
Run Code Online (Sandbox Code Playgroud)

lockf( fd, F_ULOCK, 0 )
Run Code Online (Sandbox Code Playgroud)

当应用程序以任何方式退出时,文件将自动关闭,这也会释放文件锁定.等待"信号量"的其他客户端应用程序可以按预期自由进行.

谢谢你的帮助,伙计们.


Raf*_*ian 6

使用锁定文件而不是信号量,就像@Stéphane的解决方案,但没有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");
Run Code Online (Sandbox Code Playgroud)

  • 编译错误:“error: 'O_EXLOCK' undeclared (first use in this function)”, Ubuntu16.04 LTS (3认同)
  • 好的代码,有1个修改:你应该在争用开始之前创建锁文件,当然,保持链接.否则,在Mac OS X 10.10 DP5的测试中,open()可以成功竞争最初创建文件的两个对等进程,如果在几毫秒内.问题出现在Stéphane或Raffi的代码中.然后我进行了压力测试.结果:Raffi的代码完美无缺,Stéphane的代码并不完美.我没有研究为什么.如果有兴趣,请参阅https://github.com/jerrykrinock/ClassesObjC/blob/master/SSYSemaphore.h和.m. (2认同)

Ste*_*dis 5

这是管理信号量时的典型问题。一些程序使用单个过程来管理信号量的初始化/删除。通常,此过程仅执行此操作,而不执行其他操作。您的其他应用程序可以等到信号灯可用为止。我已经看到这是通过SYSV类型的API完成的,但不是通过POSIX完成的。与提到的“ Duck ” 类似,在semop()调用中使用SEM_UNDO标志。


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