共享内存中的健壮互斥锁不是那么健壮

Robust mutex in shared memory not so robust

本文关键字:内存 共享      更新时间:2023-10-16

当通过对象使用基于pthread的健壮互斥体从一个进程到另一个进程发出信号时boost::interprocesss::managed_shared_memory我注意到存在以下问题: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:

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

场景 2:

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

问题:

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

环境:

  • Linux via Ubuntu 18.04.3 LTS
  • 海湾合作委员会 v8.3.0
  • 提升 v1.55

更新:@Jorge Bellon 发现了互斥锁/condition_variable被初始化两次的问题。解决后,该程序现在在简历中抓住 当它锁定时,堆栈跟踪显示为:

process_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

process_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

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

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

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

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

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