共享内存中的健壮互斥锁不那么健壮
Robust mutex in shared memory not so robust
当通过 boost::interprocesss::managed_shared_memory
对象使用基于 pthread 的稳健互斥锁从一个进程向另一个进程发送信号时,我注意到存在问题:a) 取决于启动顺序 and/or b) a)重新启动进程时行为发生变化。问题的症结在于,在某些情况下,我的示例应用程序中的信号(通过条件变量)没有收到。
我在 git - https://github.com/zerodefect/mutex_example 中发布了一个(最小)代码示例。我已尝试使代码示例尽可能简短,但它仍然包含几个文件。我希望在这种情况下 link 到 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
- 启动进程 B(未收到信号)
场景 2:
- 启动进程 B
- 启动进程 A(此时有效)
- 重新启动进程 B(停止接收信号)
问题:
- 我是否正确使用了 boost 的 managed_shared_memory 对象?
- 我是否正确配置了互斥量?
环境:
- Linux 通过 Ubuntu 18.04.3 LTS
- GCC v8.3.0
- Boost v1.55
更新:
@Jorge Bellon 发现 mutex/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
If remove() is never called, the shared memory continues to exist even if the program terminates. Whether or not the shared memory is automatically deleted depends on the underlying operating system. Windows and many Unix operating systems, including Linux, automatically delete shared memory once the system is restarted.
因此进程 A 尝试在 pthread_cond_wait
调用中获取 condvar 内部互斥锁 的锁,但它在之前的运行中已经被锁定。而且因为你没有退出逻辑,你肯定会杀死进程,因此永远不会释放锁。流程 B 也是如此。
您创建的互斥锁是一个强大的互斥锁这一事实无关紧要。因为它不是它,所以你被锁定等待。
......但我实际上不确定你还在等什么。不确定 condvar internal futex 的属性是什么。需要进一步调查。但从观察到的行为来看,它并不稳健。
顺便说一下,您在进程 B 中获得但不使用共享互斥锁。但是也许,只是也许,您应该 Calling pthread_cond_signal without locking mutex
还有一件事:pthread_cond_timedwait
可以 return EOWNERDEAD
并且您 必须 检查 wait_for_cv()
中的错误
当通过 boost::interprocesss::managed_shared_memory
对象使用基于 pthread 的稳健互斥锁从一个进程向另一个进程发送信号时,我注意到存在问题:a) 取决于启动顺序 and/or b) a)重新启动进程时行为发生变化。问题的症结在于,在某些情况下,我的示例应用程序中的信号(通过条件变量)没有收到。
我在 git - https://github.com/zerodefect/mutex_example 中发布了一个(最小)代码示例。我已尝试使代码示例尽可能简短,但它仍然包含几个文件。我希望在这种情况下 link 到 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
- 启动进程 B(未收到信号)
场景 2:
- 启动进程 B
- 启动进程 A(此时有效)
- 重新启动进程 B(停止接收信号)
问题:
- 我是否正确使用了 boost 的 managed_shared_memory 对象?
- 我是否正确配置了互斥量?
环境:
- Linux 通过 Ubuntu 18.04.3 LTS
- GCC v8.3.0
- Boost v1.55
更新: @Jorge Bellon 发现 mutex/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
If remove() is never called, the shared memory continues to exist even if the program terminates. Whether or not the shared memory is automatically deleted depends on the underlying operating system. Windows and many Unix operating systems, including Linux, automatically delete shared memory once the system is restarted.
因此进程 A 尝试在 pthread_cond_wait
调用中获取 condvar 内部互斥锁 的锁,但它在之前的运行中已经被锁定。而且因为你没有退出逻辑,你肯定会杀死进程,因此永远不会释放锁。流程 B 也是如此。
您创建的互斥锁是一个强大的互斥锁这一事实无关紧要。因为它不是它,所以你被锁定等待。 ......但我实际上不确定你还在等什么。不确定 condvar internal futex 的属性是什么。需要进一步调查。但从观察到的行为来看,它并不稳健。
顺便说一下,您在进程 B 中获得但不使用共享互斥锁。但是也许,只是也许,您应该 Calling pthread_cond_signal without locking mutex
还有一件事:pthread_cond_timedwait
可以 return EOWNERDEAD
并且您 必须 检查 wait_for_cv()