gpt4 book ai didi

c++ - boost interprocess_condition 多个线程调用 wait() 失败

转载 作者:行者123 更新时间:2023-11-30 03:44:41 25 4
gpt4 key购买 nike

遇到一个非常奇怪的问题,有 2 个以上的线程在等待 interprocess_condition 变量。

boost 1.60.0

  • 1 个线程调用 wait() 和第 2 个线程调用 notify_all(),一切都按预期工作。
  • 当有超过 2 次调用 wait() 时,我在 do_wait() 上遇到断言失败并且进程退出。

测试.cpp:


#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <iostream>

using namespace boost::interprocess;

struct Data {
interprocess_mutex mux_;
interprocess_condition cond_;
};

int main(int argc, char *argv[]) {
if (argc > 1 && atoi(argv[1]) == 0) {
struct shm_remove {
shm_remove() { shared_memory_object::remove("MySharedMemory"); }
~shm_remove() { shared_memory_object::remove("MySharedMemory"); }
} remover;

managed_shared_memory seg(create_only, "MySharedMemory", 65536);
Data *const d = seg.construct<Data>(unique_instance)();
scoped_lock<interprocess_mutex> lock(d->mux_);
std::cout << "Waiting" << std::endl;
d->cond_.wait(lock);
} else if (argc > 1 && atoi(argv[1]) == 1) {
managed_shared_memory seg(open_only, "MySharedMemory");
std::pair<Data *, std::size_t> res = seg.find<Data>(unique_instance);
scoped_lock<interprocess_mutex> lock(res.first->mux_);
std::cout << "Waiting" << std::endl;
res.first->cond_.wait(lock);
} else {
managed_shared_memory seg(open_only, "MySharedMemory");
std::pair<Data *, std::size_t> res = seg.find<Data>(unique_instance);
scoped_lock<interprocess_mutex> lock(res.first->mux_);
std::cout << "Notifying" << std::endl;
res.first->cond_.notify_all();
}
}

编译为:

$ clang++ -I/usr/local/include test.cpp

使用 1 个 wait() 和 1 个 notify() 运行:

$ ./a.out 0&
[8] 25889
Waiting

$ ./a.out 2&
[9] 25901
Notifying
[8]- Done ./a.out 0
[9]+ Done ./a.out 2

运行 2 次等待:

$ ./a.out 0&
[8] 25986
Waiting
$ ./a.out 1&
[9] 25998
Waiting
Assertion failed: (res == 0), function do_wait, file /usr/local/include/boost/interprocess/sync/posix/condition.hpp, line 175.

在 OSX El Capitan 上测试

$ uname -a
Darwin LUS-JOHUGHES2 15.3.0 Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64 x86_64

我还在 Ubuntu Trusty 机器上尝试了上面的示例,所有示例都按预期工作,这让我相信 OSX 实现存在问题。我没有在 Windows 上尝试过。

最佳答案

做了一些挖掘并找到了问题的明确答案。

  1. 当第二个进程调用 do_wait() 时,上面的 boost 断言错误失败,它调用 pthread_wait() 立即返回 EINVAL(而不是成功的 0)。

  2. 在 OSX 的 pthread 实现中,条件变量存储指向互斥量变量的原始指针。第一个进程中对 pthread_wait() 的第一次调用设置了该指针。对 pthread_wait() 的第二次调用根据传递给 pthread_wait() 的互斥指针检查这个存储的互斥指针。 {可以在此处的源代码中找到:https://opensource.apple.com/source/libpthread/libpthread-137.1.1/src/pthread_cond.c

  3. 由于两个进程已将共享互斥锁和条件变量映射到不同的地址空间,第二次调用 pthread_wait() 将永远不会起作用,因为它比较原始指针。

因此,使这项工作的 2 个选项如下:

  1. 使用固定地址映射:http://www.boost.org/doc/libs/1_60_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region.mapped_region_fixed_address_mapping这保证映射区域将位于同一地址,因此原始指针将起作用,或者

  2. 使用 fork() 而不是 exec() 的新进程,这意味着子进程将拥有原始段管理器的拷贝,映射到相同的地址,因此原始指针将起作用。

我没有深入研究 glibc pthreads 代码以了解它们与 Apple 有什么不同,所以我不确定为什么原始示例在 Linux 而不是 OSX 上运行。

我认为 Boost 文档肯定会受益于一段讨论这个陷阱的段落。

关于c++ - boost interprocess_condition 多个线程调用 wait() 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35305291/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com