用于共享内存一致性的锁定机制

时间:2010-06-18 15:01:29

标签: c linux locking posix shared-memory

我正在开发一种机制,用于在Linux上使用共享内存在两个或多个进程之间交换数据。问题是需要一定程度的并发控制来维护共享内存本身的数据完整性,而且由于我的某些时刻我的进程可能被杀死/崩溃,常见的锁机制不起作用,因为它们可能会留下内存处于“锁定”状态并且在死亡后立即使其他进程等待锁定被释放。

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

任何想法? :)

编辑:出于解释目的,我们的应用程序需要某种具有最小延迟的IPC机制。所以,我对可以处理这个要求的机制持开放态度。

5 个答案:

答案 0 :(得分:3)

  

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

如果进程崩溃,SEM_UNDO将解锁信号量。如果由于共享内存损坏而导致进程崩溃,则信号量无法为您做任何事情。操作系统无法撤消共享内存的状态。

如果您需要能够回滚共享内存的状态,那么您必须自己实现一些功能。我已经看过至少两个处理它的模型。

在修改共享内存中的任何内容之前的第一个模型是获取结构的快照,保存在共享内存中的列表中。如果任何其他进程能够获得锁定且列表不为空,则无论崩溃进程可能发生什么变化都会撤消。

第二个模型是在本地内存中复制shm结构并保持锁定以用于整个事务。提交事务时,在释放锁之前,只需将结构从本地内存复制到共享内存中。应用程序在复制期间崩溃的概率较低,可以使用sigprocmask()阻止外部信号的干预。 (在这种情况下锁定更好地在数据上进行了很好的分区。例如,我已经看到了对由10个并发进程访问的shm中10Mln记录的1000个锁的测试。)

答案 1 :(得分:2)

程序失败时,只有少数东西可以保证清理。这里我唯一想到的是链接数。打开文件描述符会增加底层inode的链接数,相应的close会减少它,包括程序失败时强制关闭。

所以你的进程都可以打开一个公共文件(不记得它是否适用于共享内存段),如果计数减少,你可以触发某种警报,不应该在哪里。 E.g而不是做一个简单的等待你的进程可以在一个循环中做一个timedwait(例如一秒钟),并且当某些事情出错时,会提醒链接计数。

答案 2 :(得分:1)

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

说实话,即使是可靠的信号量锁定机制也可能无法完全解决您的问题。如果你使用锁来允许事务处理,你还需要处理事务在崩溃之前中途停止的情况,并允许另一个程序访问数据结构。

答案 3 :(得分:1)

我很想知道您使用的是哪种来源说SEM_UNDO无法保证能够正常工作。我以前没有听说过。我似乎记得读过一篇文章,声称linux的SYSV IPC一般都是错误的,但那是很久以前的事了。我想知道你的信息是否只是过去的一件神器。

要考虑的另一件事(如果我没记错的话)是SYSV信号量能够告诉你执行信号量操作的最后一个进程的PID。如果你挂起,你应该能够查询以查看持有锁的进程是否仍然存在。因为任何进程(不只是持有锁的进程)都可以摆弄信号量,所以你可以用这种方式控制它。

最后,我会为消息队列添加一个音调。它们可能不适合您的速度要求,但它们通常不会比共享内存慢得多。从本质上讲,他们无论如何都要用SM手动完成所有操作,但操作系统可以完成所有操作。通过同步,原子性,易用性以及免费的经过彻底测试的机制,您可以获得几乎同样的速度。

答案 4 :(得分:1)

您可以在共享内存中使用pthread互斥锁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.txt以及http://www.kernel.org/doc/man-pages/online/pages/man7/futex.7.htmlhttp://www.kernel.org/doc/man-pages/online/pages/man2/futex.2.html,尤其是第二个,因为它涉及到让内核在发布时释放它一个让它死的过程。

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