C++ 共享内存中的健壮互斥不那么健壮

C++ 共享内存中的健壮互斥不那么健壮,c++,linux,posix,mutex,C++,Linux,Posix,Mutex,当通过boost::interprocesss::managed_shared_memory对象使用基于pthread的健壮互斥来从一个进程向另一个进程发送信号时,我注意到存在以下问题:a)取决于启动顺序和/或b)进程重新启动时的行为变化。问题的关键在于,在某些条件下,我的示例应用程序中的信号(通过条件变量)不会被接收 我已经用git-发布了一个(最少的)代码示例。我已经尽力使代码示例尽可能简短,但它仍然跨越几个文件。我希望在这个例子中链接到GitHub中的存储库是可以接受的 我有两个过程-过程

当通过
boost::interprocesss::managed_shared_memory
对象使用基于pthread的健壮互斥来从一个进程向另一个进程发送信号时,我注意到存在以下问题:a)取决于启动顺序和/或b)进程重新启动时的行为变化。问题的关键在于,在某些条件下,我的示例应用程序中的信号(通过条件变量)不会被接收

我已经用git-发布了一个(最少的)代码示例。我已经尽力使代码示例尽可能简短,但它仍然跨越几个文件。我希望在这个例子中链接到GitHub中的存储库是可以接受的

我有两个过程-过程b:

while (true)
{
    // Notify 'Process A' every 2 seconds.
    std::this_thread::sleep_for(std::chrono::seconds(2));
    pthread_cond_signal(pCv);

    std::cout << "Info: Signaled" << std::endl;
}
futex_wait 0x00007ffff7bc44b0
futex_wait_simple 0x00007ffff7bc44b0
__condvar_quiesce_and_switch_g1 0x00007ffff7bc44b0
__pthread_cond_signal 0x00007ffff7bc44b0
main main_process_b.cpp:73
__libc_start_main 0x00007ffff6fe6b97
_start 0x00005555555573aa
过程b:

while (true)
{
    // Notify 'Process A' every 2 seconds.
    std::this_thread::sleep_for(std::chrono::seconds(2));
    pthread_cond_signal(pCv);

    std::cout << "Info: Signaled" << std::endl;
}
futex_wait 0x00007ffff7bc44b0
futex_wait_simple 0x00007ffff7bc44b0
__condvar_quiesce_and_switch_g1 0x00007ffff7bc44b0
__pthread_cond_signal 0x00007ffff7bc44b0
main main_process_b.cpp:73
__libc_start_main 0x00007ffff6fe6b97
_start 0x00005555555573aa

我猜是你的代码锁,因为你从不破坏共享内存

如果从不调用remove(),则即使程序终止,共享内存仍将继续存在。是否自动删除共享内存取决于底层操作系统。Windows和许多Unix操作系统(包括Linux)在系统重新启动后会自动删除共享内存

因此,进程尝试在
pthread\u cond\u wait
调用中获取condvar internal mutex锁,但在以前的运行中它已经被锁定。因为您没有退出逻辑,所以您肯定会终止进程,因此永远不会释放锁。过程B也是如此

您创建的互斥体是健壮的互斥体这一事实与此无关。因为你等待的不是它。 ……但我真的不知道你在等什么。不确定condvar internal futex的特性是什么。需要进一步调查。但从观察到的行为来看,它并不稳健

顺便说一句,您在进程B中得到但不使用共享互斥。但是,也许,只是也许,您应该这样做
还有一件事:
pthread\u cond\u timedwait
可以返回
eownerded
,您必须检查
wait\u for_cv()中的错误

您确定需要在两个进程中初始化互斥锁吗?这对我来说似乎不合适。您可以使用
std::atomic_flag::test_and_set
,然后在且仅在先前未设置该标志的情况下初始化互斥锁。这可能是重新启动进程B无法使其工作的原因。啊,我甚至没有想到这一点!我试试看。不过,有趣的是,它最初确实根据特定的启动顺序工作,但我原以为它总是失败的。表示在这种情况下它可能会返回
EBUSY
,但错误检查和支持的性能之间的权衡部分指出,错误程序导致的错误可能不会报告,因此这可能是它不返回错误的一个很好的解释。您是对的。条件变量也需要这样做(根据文档)。进行了更改并按下,但仍根据订单将其锁定:(如果是我,我将不允许任何一个进程进行构造-我会将其限制在进程_a..上,而是在进程_b.上重试查找。这样就消除了创建时出现争用条件的可能性。根据语义,如果对象是持续创建的(即进程死亡时未清理)您可以在这两个实体中的任何一个开始之前使用单独的流程进行初始创建。这里的主要思想是将创建责任限制在一个实体上,以完全避免竞争-使用单独的流程进行初始创建将使2可靠地工作。等等,我是否误解了“健壮互斥体”的用途?我认为这样一个概念的目的是当进程停止运行时可以恢复。如果我在任何进程运行时删除共享内存,那么我将从进程的脚下拉开地毯。您可能可以使用信号处理程序在崩溃/退出时释放共享互斥体。也许“健壮”互斥体已经做到了这一点?谢谢@x00-it l像你这样的人是对的。Torvald Riegel说,“POSIX(和glibc)不指定(或提供)条件变量的健壮变体…”@Andrewattrens,这是一个想法,但我可能会看看是否可以使用信号量作为构建块来实现我自己的健壮CV。@ZeroDefect,thanx用于链接。