首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Boost interprocess_condition多线程调用wait()失败

Boost interprocess_condition多线程调用wait()失败
EN

Stack Overflow用户
提问于 2016-02-10 01:22:11
回答 2查看 906关注 0票数 2

2+线程在等待interprocess_condition变量时遇到了一个非常奇怪的问题。

升压1.60.0

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

Test.cpp:

代码语言:javascript
复制
#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();
    }
}

汇编如下:

代码语言:javascript
复制
$ clang++ -I/usr/local/include test.cpp

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

代码语言:javascript
复制
$ ./a.out 0&
[8] 25889
Waiting

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

在两个等待中运行:

代码语言:javascript
复制
$ ./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上测试

代码语言:javascript
复制
$ 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可靠的机器上尝试了上面的例子,所有的例子都像预期的那样工作,这让我相信OSX的实现有问题。我还没有在Windows上试过。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-02-13 18:45:49

做了些调查,找到了这个问题的确切答案。

  1. 当第二个进程调用do_wait()时,上面的boost断言错误失败了,后者调用了pthread_wait(),后者与EINVAL一起立即返回(而不是一个成功的0)。
  2. 在OSX的p线程实现中,条件变量存储一个指向互斥变量的原始指针。第一个进程中对pthread_wait()的第一个调用设置了这个指针。对pthread_wait()的第二个调用根据传递到pthread_wait()的互斥指针检查存储的互斥指针。{可以在源代码中找到:cond.c}
  3. 由于这两个进程在不同的地址空间中映射了共享互斥变量和条件变量,所以对pthread_wait()的第二个调用将无法工作,因为它比较原始指针。

因此,开展这项工作的两个备选方案如下:

  1. 使用固定地址映射:mapping,它保证映射的区域位于相同的地址,因此原始指针可以工作,或者
  2. 而不是exec()对新进程的使用,这意味着子进程将拥有原始段管理器的副本,映射到相同的地址,因此原始指针将工作。

我并没有深入到glibc线程代码中去了解它们与Apple的不同之处,所以我不知道为什么最初的示例在Linux上工作,而不是OSX。

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

票数 2
EN

Stack Overflow用户

发布于 2018-04-22 22:29:41

这是达尔文C库和Boost.Interprocess上的一个bug。首先,C库声称它符合posix,并且支持进程共享内存条件变量,这是假的(因为它使用原始指针来存储互斥对象的地址)。第二,Boost.Interprocess应该将这个平台检测为一个buggy,应该禁用线程的使用并回退到仿真。

在boost/interprocess/detail/workound.hpp中,您会看到一条评论:

//Mac Os X < Lion (10.7) might define _POSIX_THREAD_PROCESS_SHARED but there is no real support.

一些旧的报告声称较新的macos版本确实支持进程共享条件变量,但是这个声明是错误的,所以__APPLE__部分应该是正确的:

#define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35305291

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档