Linux IPC:共享内存恢复 [英] Linux IPC: shared memory recovery

查看:73
本文介绍了Linux IPC:共享内存恢复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个进程(生产者和消费者)通过使用 '旧' 接口而不是 mmap:

auto key = ftok(,;int ret = shmget(key, size, flags);void* memArea = shmat(key,NULL,0);//检查错误并做一些事情...

生产者进程可能因错误或配置更改而重新启动.它每次使用 shmget() 的 IPC_CREAT 标志创建一个新区域.我注意到消费者可以继续从现有的共享内存段中读取数据,而替代的生产者已经转移到另一个共享内存段.

消费者进程如何检测并从中恢复?

解决方案

改变你的生产者设计可能是更好的主意:

  • 它可以先检查是否存在可以重用的现有段,而不是使用 IPC_CREAT.

  • 您也可以考虑使用基于 mmap 的共享内存,这在某些方面更加灵活.

  • 您可以使用其他一些指标(例如锁定文件)来确定共享内存接口是否仍然可用.

但是,如果由于某种原因这些不是选项(例如其他人控制生产者代码),请继续阅读.

您可以做几件事:

  1. 使用 shmctl() 来统计"你的内存段

<块引用>

//如果共享内存区域仍然有用/可用",则返回真bool checkShm(int shmId){结构 shmid_ds statBuf;int res = shmctl(, IPC_STAT, statBuf);如果(res == -1)返回假;...

  1. 检查该区域是否被标记为删除(特定于 Linux)

<块引用>

 if ((statBuf.shm_perm.mode&SHM_DEST) != 0) return false;

  1. 假设您在生产者之后附加并且它是创建者进程 - 检查它是否在您之后分离.警告:如果您的设计允许,它可能会再次重新连接.

<块引用>

 if (statBuf.shm_cpid == shmBuf.shm_lpid) 返回false;

  1. 检查创建者进程的 PID 是否正在运行.警告:PID 可以被新进程回收

<块引用>

 if (getpgid(shmBuf.shm_cpid) == -1) return false;

注意:如果生产者不是其他用户,您可以使用 kill(shmBuf.shm_cpid,0) 代替.

  1. 您可能还想检查文件是否已被修改.一个关键点是 ftok 使用 inode 编号而不是手册页建议的实际文件名.所以你需要小心使用它:

<块引用>

struct stat fstatBuf;int res = stat(fileName,&fstatBuf);如果(res == -1)返回假;//如果文件消失了,那可能是个坏兆头!如果 (fstatBuf.st_ino !=savedInode) 返回 false;

完成所有这些后,您现在应该有一个相当好的方法来检查您认为仍然有用的 SHM 是否确实被您认为的生产者"使用.

  1. 清理陈旧的共享内存段

您现在可以自由地从段中分离 shmdt(),并尝试清理它 shmctl(shmid,IPC_RMID,NULL).如果创建者没有授权,消费者进程可能无权删除它.

  1. 附加到替换共享内存段

原则上,您可以附加到由替代生产者进程创建的任何新共享内存段:

auto key = ftok(,;void* memArea = shmat(key,NULL,0);//检查错误并做一些事情...

但是等待着你的是残酷而有趣的惩罚.它不会立即起作用.您必须等待一段时间并定期重试.我猜这是直到操作系统有机会清理旧的内存段.

我发现 ftok() 在一段时间内返回 -1,尽管文件存在并且与原始文件具有相同的 inode.

I have two processes (a producer and a consumer) communicating via a shared memory segment produced using the 'old' interface rather than mmap:

auto key = ftok(<somefile>,<someid>;
int ret = shmget(key, size, flags);
void* memArea = shmat(key,NULL,0);
// check errors and do stuff...

The producer process could be restarted due to an error or configuration change. It creates a new region each time using the IPC_CREAT flag to shmget(). I have noticed that the consumer can continue to read from the existing shared memory segment while the replacement producer has moved on to a different one.

How can a consumer process detect and recover from this?

解决方案

It might be better idea to alter your producer design:

  • Instead of using IPC_CREAT it could first check if there is an existing segment that could be re-used.

  • You could also consider using mmap based shared memory instead which is more flexible in some ways.

  • You could use some other indicator such as a lock file to determine if the shared memory interface is still viable.

However, if for some reason these are not options (someone else controls the producer code for example) then read on.

There are several things you can do:

  1. use shmctl() to 'stat' your memory segment

 // return true if the shared memory region is still 'useful/useable'
 bool checkShm(int shmId)
 {
     struct shmid_ds statBuf;
     int res = shmctl(<shmid>, IPC_STAT, statBuf);
     if (res == -1) return false;
     ...

  1. check if the region is marked for deletion (Linux specific)

 if ((statBuf.shm_perm.mode&SHM_DEST) != 0) return false;

  1. assuming you attached after the producer and it is the creator process - check that it dettached after you. caveat: It could have reattached again if your design allows this.

 if (statBuf.shm_cpid == shmBuf.shm_lpid) return false;

  1. check the PID of the creator process is a running process. caveat: the PID could be recycled by a new process

 if (getpgid(shmBuf.shm_cpid) == -1) return false;

note: you could use kill(shmBuf.shm_cpid,0) instead if the producer is not a different user.

  1. You might also want to check if the file has been modified. A key point is that ftok uses the inode number not the actual filename as the man page suggests. So you need to be careful using it:

struct stat fstatBuf;
int res = stat(fileName,&fstatBuf);
if (res == -1) return false; // if the file has disappeared it could be a bad sign!
if (fstatBuf.st_ino != savedInode) return false;

Having done all this you should now have a reasonably good way to check if the SHM you think is still useful is actually being used by the 'producer' you think it is.

  1. Clean up the stale shared memory segmant

You are now free to detach shmdt() from the segment, and try to clean it up shmctl(shmid,IPC_RMID,NULL). The consumer process might not have permissions to remove it if the creator did not grant them.

  1. Attach to the replacement shared memory segment

You are then in principle able to attach to any new shared memory segment created by a replacement producer process:

auto key = ftok(<somefile>,<someid>;
void* memArea = shmat(key,NULL,0);
// check errors and do stuff...

But there a cruel and interesting punishment awaits you. It will not work immediately. You have to wait a time and periodically retry. I guess this is until the operating system has had a chance to clean up the old memory segment.

I found that ftok() returns -1 for a while despite the file existing and having the same inode as the original file.

这篇关于Linux IPC:共享内存恢复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆