2010-06-18 119 views
8

我正在开发一种在Linux上使用共享内存的两个或多个进程之间交换数据的机制。问题是需要一定程度的并发控制来保持共享内存本身的数据完整性,并且正如我在某个时间或其他地方所指出的那样,我的进程可能会被杀死/崩溃,所以常见的锁机制不工作,因为它们可能会留下内存处于“锁定”状态并在临终之后,使其他进程等待锁被释放。共享内存一致性的锁定机制

因此,做了一些研究后,我发现System V信号量有一个名为SEM_UNDO的标志,当程序失败时它可以恢复锁定状态,但这并不保证能正常工作。另一种选择是监视可能使用共享内存的所有进程的PID,并在发生不愉快事件时对其进行一些控制,但我不确定这是否是解决我的问题的正确方法。

任何想法?? :)

编辑:为了解释的目的,我们的应用程序需要某种类型的IPC机制尽可能最小的延迟。所以,我也开放了可以处理这一要求的机制。

+0

另一种方法是不使用共享内存 - 我从来没有理解它似乎对程序员的可怕魅力。还有很多其他的IPC机制(一些在共享内存上预先构建和测试过),那么为什么不使用它们呢? – 2010-06-18 15:07:18

+1

为了表现。我们的应用程序需要处理微秒级的延迟。有IPC机制可以实现这种性能? – scooterman 2010-06-18 16:42:04

+0

@scooterman您正在使用哪种实时Linux变体? – 2010-06-18 16:47:59

回答

0

我会很好奇,知道你说的SEM_UNDO不能保证工作的源码。我以前没有听说过。我似乎记得阅读声称Linux的SYSV IPC的文章通常是越野车,但那是相当一段时间以前。我在想,如果你的信息只是过去的时代的神器。

要考虑的其他事情(如果我没有记错的话)是SYSV信号量能够告诉您执行信号操作的最后一个进程的PID。如果你挂了,你应该能够查询,看看持有锁的进程是否还活着。由于任何进程(不仅仅是持有锁的进程)都可以摆弄信号量,所以你可以通过这种方式进行控制。

最后,我将放入消息队列。它们可能不适合您的速度要求,但它们通常不会比共享内存慢得多。实质上,他们正在尽你所能地用SM手动执行任何操作,但操作系统将它全部放在封面下面。同步,原子性,易用性以及经过全面测试的免费机制您的速度几乎相同。

+0

我会将此视为已接受,因为我已切换到消息队列并发现它适合我的需求。谢谢 – scooterman 2010-06-23 21:16:48

2

只有几件事情可以保证从程序失败中清理干净。这里我唯一想到的就是链接数量。一个打开的文件描述符会增加底层inode的链接数量,相应的关闭会降低它,包括程序失败时强制关闭。

所以,你的过程可以全部打开一个共同文件(不记得它是否适合共享内存段),如果计数减少,它应该不是你可能会引发某种报警。例如,不要简单地等待你的进程可以在一个循环中等待一段时间(例如一秒钟),并且在有些事情出错时轮询链接计数。

+0

如果您正确使用futexes,内核将清理它们 – Spudd86 2010-06-18 18:20:04

+0

问题用posix标记。 IIRC futexes是纯粹的linux结构,不能移植到其他POSIX系统。 – 2010-06-18 18:27:42

+0

经过一番思考,实际上存在一个POSIX兼容的锁结构,并保证在进程终止时清理:通过fcntl方式建立咨询文件锁。它们使用起来有点棘手(陷阱:当同一个inode上的任何fd被进程的任何线程关闭时,你会释放一个锁),但是完全在内核空间中实现,而没有实际写入磁盘。 – 2010-06-19 06:34:19

1

当你声明信号量不能干净地处理进程时,我有点惊讶。这种支持似乎相当重要!在我的ubuntu 10.4系统和网页here上查看semop手册页似乎表明它应该没问题。希望用于存储SEM_UNDO计数的内存存储在内核空间中,因此可以避免错误的内存写入。

虽然真相被告知,即使是可靠的信号量锁定机制也可能无法完全解决您的问题。如果您使用锁来允许事务处理,那么您还需要处理事务在崩溃之前中途停止并允许其他程序访问数据结构的情况。

+0

对不起,还没有找到我从哪里来的来源。尽管系统IV信号量有限制,可以由进程保留大约37k个SEM_UNDO结构,所以它无法工作,因为我的应用程序可以快速写入这些数量的消息。不管怎么说,还是要谢谢你。 – scooterman 2010-06-23 21:21:48

1

您可以使用共享内存并行线程互斥pthread_mutexattr_setpshared(http://linux.die.net/man/3/pthread_mutexattr_setpshared

你也可以尝试使用futexes的直接看到http://people.redhat.com/drepper/futex.pdfhttp://lxr.linux.no/#linux+v2.6.34/Documentation/robust-futexes.txthttp://www.kernel.org/doc/man-pages/online/pages/man7/futex.7.htmlhttp://www.kernel.org/doc/man-pages/online/pages/man2/futex.2.html particularaly第二个自认为有关获取内核释放会谈它在持有它的过程中死亡。

另外,我认为可以使pthreads锁/ CV变得健壮,这是一个更好的主意,因为那时处理强健锁的所有东西都是为你完成的(在一个甚至是现代化的发行版中,它应该使用强健的futexs在http://lxr.linux.no/#linux+v2.6.34/Documentation/robust-futexes.txt为pthread_mutex IIRC描述,因为这一直是在内核相当长一段时间,但你可能想确保你不需要做任何事来让你的pthread_mutex稳健)

3

所以,做一些研究,我我们发现System V信号量有一个名为SEM_UNDO的标志,当程序失败时它可以恢复锁定状态,但这并不保证能够正常工作。

如果进程崩溃,SEM_UNDO将解锁信号量。如果进程因共享内存损坏而崩溃,则没有任何信号量可以为您执行操作。操作系统无法撤销共享内存的状态。

如果你需要能够回滚共享内存的状态,那么你必须自己实现一些东西。我已经看到至少有两个处理这个问题的模型。

修改共享内存中任何内容之前的第一个模型是拍摄结构的快照,并保存在共享内存的列表中。如果任何其他进程能够获得该锁并且该列表不是空的,则它将撤销任何崩溃的进程可能已经改变的情况。

第二种模式是在本地内存中创建shm结构的副本并锁定整个事务的锁定。当提交事务时,在释放锁之前,只需将本地内存中的结构复制到共享内存中即可。应用程序在复制期间崩溃的可能性较低,并且可以使用sigprocmask()来阻止外部信号的干预。 (在这种情况下,最好锁定在数据上,例如我已经看到测试使用1000个锁进行10Mln记录,并通过4个并发进程访问shm。)

+0

非常有趣的东西。谢谢! – scooterman 2010-06-23 21:17:11