Я разрабатываю для iOS в XCode 4.6. Я пишу библиотеку для службы и использую 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 ++, я был бы рад каждой части информации о том, в чем причина, как ее отладить и как знать, если эта проблема появится в следующий раз. Также я не совсем уверен, какая информация актуальна. То, что я понял, может быть уместно из того, что я нашел там, следующее может: ResultListener
а также Service
являются boost::noncopyable
, Я проверил счетчик ссылок shared_ptr
(с помощью use_count
) и оно увеличивается в продолжении. Я использую Boost 1,53. Метод называется так
Servuce reco(/* ... */);
boost::shared_ptr<foo> f(new foo());
reco.start(f);
foo
будучи простым классом, который ничего не делает, кроме печати в std::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, и кажется, что Манкарнас (в комментариях) и я (выше) правы: кажется, часть памяти, в которой хранится продолжение освобождается и, следовательно, происходит неопределенное поведение.
Это ситуация до get()
называется:
Это ситуация после get()
назывался:
Адрес px
указывает на это 0x00
после этого.
Я открыл билет против повышения 1,53 и это было подтверждено как ошибка. Кажется, что future.then
еще не стабилен и поэтому не готов к использованию. Один совет оттуда был использовать
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
Но было четко заявлено, что эта функция еще не стабильна (и что в документации не хватает этой информации).
Сейчас я переключился на использование отдельного потока, в котором я буду ждать будущего и затем выполню соответствующие действия.
Других решений пока нет …