5

我正在 XCode 4.6 中为 iOS 开发。我正在为服务编写一个库并使用 boost 来启动线程。我的一种方法如下所示:

void Service::start(boost::shared_ptr<ResultListener> listener) {

    boost::future<bool> con = boost::make_future(true);
    listener->onConnected(); // Works
    boost::future<bool> initDone = con.then([&, listener](boost::future<bool>& connected) {
         listener->onConnected(); // Works
         if (!connected.get()) {
             listener->onError("...");
             return false;
         }
         listener->onError("...");  // EXC_BAD_ACCESS
         /* ... */
         return true;
    });
}

在设备上执行此操作时,我EXC_BAD_ACCESS在标记的行处得到一个。我对此感到非常惊讶,因为第一次调用onConnected是成功的,即使我在那个onError调用之前添加了一个调用if也是如此。

由于对 C++ 非常缺乏经验,我会对每条关于原因是什么、如何调试它以及如何知道下次是否出现此问题的信息感到高兴。我也不太确定哪些信息是相关的。我想出的可能与我迄今为止发现的有关,以下可能:ResultListenerServiceboost::noncopyable。我检查了shared_ptr(using use_count) 的引用计数,它在继续中增加。我正在使用提升 1.53。方法是这样调用的

Servuce reco(/* ... */);
boost::shared_ptr<foo> f(new foo());
reco.start(f);

foostd::cout作为一个简单的类,如果调用了方法,除了打印到之外什么都不做。

编辑:进一步窥探让我检查get()调用,我发现future.hpp正在执行以下代码:

    // retrieving the value
    move_dest_type get()
    {
        if(!this->future_)
        {
            boost::throw_exception(future_uninitialized());
        }

        future_ptr fut_=this->future_;
        this->future_.reset();
        return fut_->get();
    }

我认为这是问题所在。调用reset()似乎释放了future_ shared_ptr. 我的猜测是,这将继续运行的内存标记为未用于操作系统,从而使listener指针无效,然后将指针作为内存访问超出其范围。这个假设正确吗?我可以以某种方式避免这种情况还是这是提升中的错误?

编辑 2:以下是创建问题的最小示例:

#define BOOST_THREAD_VERSION 4
#include <boost/thread.hpp>

class Test {

public:
    void test() {
        boost::shared_ptr<Test> listener(new Test());
        boost::future<bool> con = boost::make_future(true);
        listener->foo(); // Works
        boost::future<bool> initDone = con.then([listener](boost::future<bool>& connected) {
            listener->foo(); // Works
            if (!connected.get()) {
                listener->foo();
                return false;
            }
            listener->foo();  // EXC_BAD_ACCESS
            return true;
        });
    }

    void foo() {
        std::cout << "foo";
    }
};

我添加了我在 XCode 中拍摄的两个屏幕截图,以显示未来正在运行 conitnuation 的情况,并且 Mankarnas(在评论中)和我(上图)似乎是正确的:似乎是存储 continuation 的内存部分被释放,因此发生未定义的行为。

这是之前get()称为的情况: <code>get</code> 调用前的情况

这是get()调用后的情况: <code>get</code> 被调用后的情况

地址px指向的是0x00之后。

4

1 回答 1

2

我开了一张针对 boost 1.53 的票,它被确认为一个错误。它似乎future.then还不稳定,因此还没有准备好用于生产。那里的一个建议是使用

#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET

但是明确指出此功能还不稳定(并且文档缺少这一点信息)。

我现在已经切换到使用单独的线程,我将在其中等待未来并执行正确的操作。

于 2013-02-18T08:06:45.633 回答