当将信号量减为零的进程崩溃时,如何恢复信号量?
- 2024-11-01 08:41:00
- admin 原创
- 39
问题描述:
我有多个使用 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
以下是我减少它的方法:
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";
}
解决方案 1:
事实证明,没有办法可靠地恢复信号量。当然,任何人都可以post_sem()
对命名信号量进行操作,使计数再次超过零,但如何判断何时需要进行这种恢复?提供的 API 太有限,无法以任何方式指示何时发生了这种情况。
请注意,还有 ipc 工具可用——常用工具ipcmk
、ipcrm
和ipcs
仅适用于过时的 SysV 信号量。它们特别不适用于新的 POSIX 信号量。
但似乎还有其他东西可用于锁定事物,当应用程序以一种无法被信号处理程序捕获的方式死亡时,操作系统会自动释放这些事物。两个例子:绑定到特定端口的监听套接字,或特定文件上的锁定。
我认为文件上的锁定是我需要的解决方案。因此,我没有使用sem_wait()
andsem_post()
调用,而是使用:
lockf( fd, F_LOCK, 0 )
和
lockf( fd, F_ULOCK, 0 )
当应用程序以任何方式退出时,文件将自动关闭,同时释放文件锁。然后等待“信号量”的其他客户端应用程序就可以自由地按预期继续运行。
谢谢大家的帮助。
更新:
12 年后,我认为我应该指出 posix 互斥锁确实具有“健壮”属性。这样,如果互斥锁的所有者被杀死或退出,下一个锁定互斥锁的用户将获得非错误返回值EOWNERDEAD
,从而允许恢复互斥锁。这将使其类似于文件和套接字锁定解决方案。查看pthread_mutexattr_setrobust()
和pthread_mutex_consistent()
了解详细信息。感谢 Reinier Torenbeek 提供的提示。
解决方案 2:
使用锁定文件而不是信号量,与 @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.
");
//Do "critical" stuff here.
//...
//exit the critical section
errno = 0;
if (close(fd) == -1) {
perror("close() failed");
exit(EXIT_FAILURE);
}
printf("Exited critical section.
");
解决方案 3:
这是管理信号量时的一个典型问题。一些程序使用单个进程来管理信号量的初始化/删除。通常,此进程只执行此操作,不执行其他任何操作。您的其他应用程序可以等到信号量可用。我见过使用 SYSV 类型 API 完成此操作,但未见过使用 POSIX 完成此操作。与“ Duck ”提到的类似,在 semop() 调用中使用 SEM_UNDO 标志。
但是,根据您提供的信息,我建议您不要使用信号量。特别是当您的进程有被终止或崩溃的危险时。尝试使用操作系统会自动为您清理的东西。
解决方案 4:
您需要仔细检查,但我相信 sem_post 可以从信号处理程序调用。如果您能够捕捉到导致进程停止的一些情况,这可能会有所帮助。
与互斥锁不同,任何进程或线程(具有权限)都可以向信号量发送消息。您可以编写一个简单的实用程序来重置它。假设您知道系统何时死锁。您可以关闭它并运行实用程序。
信号电话通常列在 /dev/shm 下,您可以将其删除。
SysV 信号量更适合这种情况。您可以指定 SEM_UNDO,这样系统将撤消进程对信号量所做的更改(如果进程终止)。它们还可以告诉您更改信号量的最后一个进程 ID。
解决方案 5:
您应该能够使用 从 shell 中找到它lsof
。那么您可以删除它吗?
更新
啊,是的...man -k semaphore
来救援。
似乎您可以使用ipcrm
来摆脱信号量。看来您不是第一个遇到这个问题的人。
解决方案 6:
如果该进程被终止,那么就没有任何直接的方法来确定它已经消失。
您可以对所有信号量进行某种定期完整性检查 - 使用semctl (cmd=GETPID) 查找最后一个接触您描述状态的每个信号量的进程的 PID,然后检查该进程是否仍然存在。如果不存在,请执行清理。
解决方案 7:
lsof
如果使用命名信号量,那么您可以使用类似于或中使用的算法fuser
。
请考虑以下几点:
1.每个命名的 POSIX 信号量通常在以下路径下在 tmpfs 文件系统中创建一个文件:
/dev/shm/
2.linux中每个进程都有一个map_files,位于路径下:
/proc/[PID]/map_files/
这些映射文件显示了进程内存的哪一部分映射到什么!
因此,使用这些步骤,您可以找到命名的信号量是否仍由另一个进程打开:
1-(可选)查找命名信号量的确切路径(如果它不在/dev/shm
)
首先在新进程中打开命名信号量,并将结果赋给一个指针
找到内存中指针的地址位置(通常将指针的地址转换为整数类型)并将其转换为十六进制(即结果:)
0xffff1234
数字,然后使用此路径:
/proc/self/map_files/ffff1234-*
应该只有一个文件满足此条件。
获取该文件的符号链接目标。它是命名信号量的完整路径。
2- 遍历所有进程以查找其符号链接标记与指定信号量的完整路径匹配的映射文件。如果存在,则表示该信号量正在实际使用中,但如果没有,则可以安全地取消链接指定信号量并重新打开它以供使用。
更新
在步骤 2 中,当遍历所有进程时,最好不要遍历文件夹 中的所有文件map_file
,而是使用文件/proc/[PID]/maps
并在其中搜索命名信号量文件(即:)的完整路径/dev/shm/sem_xyz
。在这种方法中,即使其他一些程序取消了命名信号量的链接,但该信号量仍在其他进程中使用,它仍然可以被找到,但其文件路径末尾会附加一个“(已删除)”标志。
解决方案 8:
sem_unlink()
只需在 之后立即执行sem_open()
。Linux 将在所有进程关闭资源后删除,其中包括内部关闭。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件