不使用时删除POSIX共享内存?

有没有什么办法,特定于linux,有posix共享内存段(用shm_open()获得),当没有进程正在使用它们。 即当参考值变为0时,将其引用计数并使系统去除它们

一些注意事项:

不 – 在Linux上,内核不包含任何可以做到这一点的东西。 有些应用程序需要在某个时候调用shm_unlink()来摆脱共享内存段。

如果程序在执行时有一点是众所周知的,那么所有需要打开共享内存段的进程都已经这样做了,您可以放心地将其解除链接。 取消链接会将对象从全局名称空间中删除,但只要至少有一个进程保持其文件描述符处于打开状态,它就会继续存在。 如果在该点之后发生崩溃,则文件描述符将自动关闭,并且引用计数递减。 一旦不存在未链接的共享内存块的开放描述符,则将其删除。

这在以下场景中很有用:一个进程创建一个共享内存块,将其解除链接然后分叉。 孩子继承文件描述符,并可以使用共享内存块与父进行通信。 一旦这两个进程终止,当两个文件描述符关闭时,块将自动删除。

虽然未链接,但共享内存块不可用于其他进程打开它。 同时,如果使用与未链接块同名的shm_open() ,则会创建一个新的完全不同的共享内存块。

我找到了一个使用系统命令和Linux命令“fuser”的方法,它允许列出打开文件的进程。 这样,您可以检查共享内存文件(位于/ dev / shm中)是否仍在使用,如果不是,则删除它们。请注意,check / delete / create操作必须包含在进程间临界区使用命名的互斥锁或命名的信号量或文件锁定。

  std::string shm_file = "/dev/shm/" + service_name + "Shm"; std::string cmd_line = "if [ -f " + shm_file + " ] ; then if ! fuser -s " + shm_file + " ; then rm -f " + shm_file + " ; else exit 2 ; fi else exit 3 ; fi"; int res = system(cmd_line.c_str()); switch (WEXITSTATUS(res)) { case 0: _logger.warning ("The shared memory file " + shm_file + " was found orphan and is deleted"); break; case 1: _logger.critical("The shared memory file " + shm_file + " was found orphan and cannot be deleted"); break; case 2: _logger.trace ("The shared memory file " + shm_file + " is linked to alive processes"); break; case 3: _logger.trace ("The shared memory file " + shm_file + " is not found"); break; } 

对于使用sysV API创建的共享内存,可能会有这样的行为。 仅在Linux上。 这不是POSIX共享内存,但可以为你工作。

在“Linux编程接口”一书中,对shmctl()的可能参数之一进行了如下描述。

IPC_RMID将共享内存段及其关联的shmid_ds数据结构标记为删除。 如果当前没有任何进程已经附加了该段,则立即删除; 否则,在所有进程已经分离之后(即,当shmid_ds数据结构中的shm_nattch字段的值下降到0时),该分段被移除。 在某些应用程序中,我们可以确保在应用程序终止时将共享内存段整理清除,方法是在所有进程都使用shmat()将其附加到其虚拟地址空间后立即将其标记为删除。 这与我们打开文件后取消链接文件类似。 在Linux上,如果共享段已被标记为使用IPC_RMID进行删除,但尚未被删除,因为某个进程仍附加了该进程,则可能是另一个进程附加了该段。 但是,这种行为是不可移植的:大多数UNIX实现阻止新添加到标记为删除的段。 (SUSv3没有提到在这种情况下应该发生什么行为)。一些Linux应用程序已经开始依赖这种行为,这就是为什么Linux没有被更改为与其他UNIX实现相匹配的原因。

你不能只使用全局计数信号来引用计数吗? 包装附加和分离呼叫,以便信号量在附加到内存时递增,在分离时递减。 当分离将信号量减少到零时释放分段。

不确定,如果下面的工作,或可行。 但是我的尝试。

为什么不执行助手程序,每当程序崩溃时执行。

即:

 /proc/sys/kernel/core_pattern to /path/to/Myprogram %p 

我的程序在进程崩溃时执行,可能你可以进一步探索。

看到

 man 5 core. for more information. 

希望这有助于一些延伸。

让我们假设最复杂的情​​况:

  • 您有几个进程通过共享内存进行通信
  • 他们可以随时开始和结束,甚至多次。 这意味着没有主进程,也没有可以初始化共享内存的专用“第一”进程。
  • 这意味着,例如,您可以安全地取消共享内存链接,因此无论是Sergey还是Hristo的答案都无效。

我看到两个可能的解决方案,并欢迎他们的反馈,因为互联网在这个问题上是沉默的:

  1. 将写入共享内存中共享内存的最后一个进程的pid(或者一个更具体的进程标识符)存储为一个锁。 那你可以做某事 像下面的伪代码一样:

     int* pshmem = open shared memory() while(true) nPid = atomic_read(pshmem) if nPid = 0 // your shared memory is in a valid state break else // process nPid holds a lock to your shared memory // or it might have crashed while holding the lock if process nPid still exists // shared memory is valid break else // shared memory is corrupt // try acquire lock if atomic_compare_exchange(pshmem, nPid, my pid) // we have the lock reinitialize shared memory atomic_write(pshem, 0) // release lock else // somebody else got the lock in the meantime // continue loop 

    这证实了上一位作家在写作时没有死亡。 共享内存仍然比任何进程持续更久。

  2. 使用读取器/写入器文件锁定来确定是否有任何进程是打开共享内存对象的第一个进程。 第一个进程可能会重新初始化共享内存:

     // try to get exclusive lock on lockfile int fd = open(lockfile, O_RDONLY | O_CREAT | O_EXLOCK | O_NONBLOCK, ...) if fd == -1 // didn't work, somebody else has it and is initializing shared memory // acquire shared lock and wait for it fd = open(lockfile, O_RDONLY | O_SHLOCK) // open shared memory else // we are the first // delete shared memory object // possibly delete named mutex/semaphore as well // create shared memory object (& semaphore) // degrade exclusive lock to a shared lock flock(fd, LOCK_SH) 

    文件锁似乎是POSIX系统上唯一的(?)机制,在进程死亡时会自动清理。 不幸的是, 使用它们的注意事项非常非常长 。 该算法假定至少在本地机器上的底层文件系统上支持flock 。 该算法不关心锁定是否对NFS文件系统上的其他进程实际可见。 它们只能在访问共享内存对象的所有进程中可见。