我有多个用g++编译的应用程序,运行在Ubuntu中,我使用命名信号量来协调不同的进程。
除以下情况外,所有工程均良好:如果其中一个进程调用sem_wait()
或sem_timedwait()
来递减信号量,然后在它有机会调用sem_post()
之前崩溃或被终止-9,那么从那一刻起,命名的信号量是“不可用的”。
所谓“不可用”,我的意思是信号量计数现在为零,而本应将其递增回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";
}
8条答案
按热度按时间hfsqlsce1#
事实证明,没有一种方法可以可靠地恢复信号量。当然,任何人都可以对指定的信号量执行
post_sem()
操作,以使计数再次增加到零以上,但如何判断何时需要进行这样的恢复?提供的API太有限,并且无法以任何方式指示何时发生了这种情况。要注意也可以使用的ipc工具--常用工具
ipcmk
、ipcrm
和ipcs
只用于过时的SysV信号量,特别是它们不能与新的POSIX信号量一起使用。但看起来还有其他东西可以用来锁定东西,当应用程序以信号处理程序无法捕捉的方式死亡时,操作系统会自动释放这些东西。绑定到特定端口的侦听套接字或特定文件上的锁。
我决定锁定文件是我需要的解决方案。因此,我使用的不是
sem_wait()
和sem_post()
调用,而是:和
当应用程序以任何方式退出时,文件会自动关闭,这也会释放文件锁定。等待“信号量”的其他客户端应用程序随后可以按预期自由地继续运行。
谢谢你们的帮助,伙计们。
最新消息:
12年后,我想我应该指出posix互斥体确实有一个“健壮”属性,这样,如果互斥体的所有者被杀死或退出,下一个锁定互斥体的用户将获得
EOWNERDEAD
的非错误返回值,允许恢复互斥锁。这将使它类似于文件和套接字锁定解决方案。有关详细信息,请查看pthread_mutexattr_setrobust()
和pthread_mutex_consistent()
。谢谢,雷尼尔·托伦贝克,这个提示。nimxete22#
使用一个锁文件代替信号量,很像@Stéphane的解决方案,但是没有flock()调用,你可以使用一个独占锁打开文件:
yb3bgrhw3#
这是管理信号量时的一个典型问题。一些程序使用一个进程来管理信号量的初始化/删除。通常这个进程只做这个,不做别的。你的其他应用程序可以等到信号量可用。我见过SYSV类型的API这样做,但POSIX没有。类似于'Duck'提到的,在semop()调用中使用SEM_UNDO标志。
**但是,**根据您提供的信息,我建议您不要使用信号量。特别是当您的进程有被终止或崩溃的危险时。请尝试使用操作系统会自动为您清理的内容。
lztngnrs4#
您需要仔细检查,但我相信sem_post可以从信号处理程序中调用。如果您能够捕捉到一些导致进程停止的情况,这可能会有所帮助。
与互斥锁不同的是,任何进程或线程(有权限)都可以向信号量发送信息。您可以编写一个简单的实用程序来重置它。想必您知道系统何时出现死锁。您可以关闭它并运行实用程序。
此外,信号通常列在/dev/shm下,您可以删除它。
SysV信号量更适合这种情况。您可以指定SEM_UNDO,如果进程终止,系统将取消进程对信号量所做的更改。它们还可以告诉您最后一个进程ID以更改信号量。
n1bvdmb65#
你应该可以用
lsof
从shell中找到它。然后你可以删除它吗?更新
啊,是的......
man -k semaphore
来拯救。看起来你可以用
ipcrm
来去掉一个信号量。看起来你不是第一个遇到这个问题的人。wgxvkvu96#
如果进程被终止,那么将没有任何直接的方法来确定它已经消失。
你可以对所有的信号量进行某种周期性的完整性检查--使用semctl(cmd=GETPID)来找到最后一个进程的PID,这个进程在你描述的状态下接触了每个信号量,然后检查这个进程是否还在,如果没有,就执行清理。
cld4siwp7#
如果使用命名信号量,则可以使用类似于
lsof
或fuser
中使用的算法。请考虑以下几点:
1.每个命名的POSIX信号量在tmpfs文件系统中创建一个文件,通常位于以下路径下:
2.每个进程在linux中都有一个map_files,路径为:
这些Map文件,显示了一个进程内存Map到什么的哪一部分!
因此,使用这些步骤,您可以发现命名的信号量是否仍由另一个进程打开:
1-(可选)查找已命名信号量的确切路径(如果它不在
/dev/shm
下)0xffff1234
)编号,然后使用以下路径:/proc/self/map_files/ffff1234-*
应该只有一个文件满足此标准。
2-遍历所有进程以找到一个Map文件,该文件的符号链接目标与指定信号量的完整路径相匹配。如果存在一个Map文件,则该信号量真实的上正在使用,但如果没有Map文件,则可以安全地取消指定信号量的链接,然后重新打开它以供使用。
更新
在步骤2中,当迭代所有进程时,最好使用文件
/proc/[PID]/maps
并搜索指定信号量文件的完整路径(即:/dev/shm/sem_xyz
)。在该方法中,即使一些其他程序取消了已命名信号量的链接,但该信号量仍在其他进程中使用,仍然可以找到该信号量,但在其文件路径的末尾附加了“(已删除)”标志。rjee0c158#
只需在
sem_open()
之后立即执行sem_unlink()
。Linux将在所有进程关闭资源(包括内部关闭)后删除。