首页 > 解决方案 > 共享内存中的健壮互斥体不是那么健壮

问题描述

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

我在 git - https://github.com/zerodefect/mutex_example中发布了一个(最小)代码示例。我试图使代码示例尽可能简短,但它仍然跨越几个文件。我希望在这种情况下链接到 GitHub 中的存储库是可以接受的吗?

我有 2 个进程 - process_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;
}

它只是试图向 process_a 发出信号:

while (true)
{
    if (!timed_lock_mutex(pMutex, std::chrono::seconds(5)))
    {
        std::cout << "Warning: Mutex wait timeout." << std::endl;
        continue;
    }

    BOOST_SCOPE_EXIT(pMutex)
    {
        unlock_mutex(pMutex);
    } BOOST_SCOPE_EXIT_END

    if (!wait_for_cv(pCv, pMutex, std::chrono::seconds(10)))
    {
        std::cout << "Warning: Wait timeout!" << std::endl;
        continue;
    }

    std::cout << "Info: Received notification." << std::endl;
}

问题场景

场景一:

  1. 启动过程 A
  2. 启动进程 B(未收到信号)

场景二:

  1. 启动流程 B
  2. 启动流程A(此时工作)
  3. 重启进程B(信号停止接收)

问题:

  1. 我是否正确使用了 boost 的 managed_shared_memory 对象?
  2. 我是否正确配置了互斥锁?

环境:

更新: @Jorge Bellon 发现了 mutex/condition_variable 被初始化两次的问题。解决后,程序现在在 CV 中被卡住时,堆栈跟踪显示为:

进程_a:

futex_wait 0x00007ffff7bc3602
futex_wait_simple 0x00007ffff7bc3602
__condvar_acquire_lock 0x00007ffff7bc3602
__condvar_cancel_waiting 0x00007ffff7bc3602
__pthread_cond_wait_common 0x00007ffff7bc40bd
__pthread_cond_timedwait 0x00007ffff7bc40bd
wait_until cv_utils.cpp:73
wait_for_cv cv_utils.cpp:93
main main_process_a.cpp:85
__libc_start_main 0x00007ffff6fe6b97
_start 0x000055555555734a

进程_b:

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

标签: c++linuxposixmutex

解决方案


我的猜测是您的代码锁定,因为您从不破坏共享内存 https://theboostcpplibraries.com/boost.interprocess-shared-memory

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

因此,进程 A 尝试在调用中获取condvar 内部互斥锁pthread_cond_wait,但它在之前的运行中已经被锁定。而且因为你没有退出逻辑,你肯定会杀死进程,因此永远不会释放锁。过程 B 也是如此。

您创建的互斥锁是健壮的互斥锁这一事实无关紧要。因为它不是你被锁定等待。...但我实际上不确定你还在等什么。不确定 condvar 内部 futex 的属性是什么。需要进一步调查。但从观察到的行为来看,它并不稳健。

顺便说一句,您在进程 B 中获得但不使用共享互斥锁。但也许,只是也许,您应该在不锁定互斥锁的情况下调用 pthread_cond_signal 还有一件事:pthread_cond_timedwait可以返回EOWNERDEAD,您必须在您的wait_for_cv()


推荐阅读