2013-02-12 13 views
5

Pracuję dla iOS w XCode 4.6. Piszę bibliotekę dla usługi i używam boost, aby rozpocząć wątki. Jedną z moich metod wygląda następująco:Zły dostęp w boost :: future <>. Then then() po uzyskaniu dostępu do danej przyszłości

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; 
    }); 
} 

Podczas wykonywania tego urządzenia dostaję EXC_BAD_ACCESS w zaznaczonym wierszu. Bardzo mnie to zaskoczyło, ponieważ pierwsze wywołanie onConnected zakończyło się sukcesem i nawet jeśli dodam wywołanie onError przed if, to także działa.

Będąc dość niedoświadczonym w C++, byłbym zadowolony z każdej informacji o tym, co jest powodem, jak go debugować i jak być świadomym, czy ten problem będzie następnym razem. Również nie jestem pewien, które informacje są istotne. To, co wymyśliłem, może być istotne z tego, co odkryłem tak daleko, że mogą być następujące: ResultListener i Serviceboost::noncopyable. Sprawdziłem liczbę referencyjną shared_ptr (używając use_count) i wzrasta ona w ramach kontynuacji. Używam doładowania 1.53. Metoda nazywa się tak

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

foo jest prosta klasa, która nie robi nic innego, jak drukować na std::cout jeśli metoda jest wywoływana.

Edit: Dalsze węszyć pozwól, aby sprawdzić połączenie get() i znalazłem następujący kod w future.hpp wykonywane:

// 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(); 
    } 

myślę, że to jest problem. Wywołanie reset() wydaje się zwalniać pamięć future_shared_ptr. Przypuszczam, że to oznacza pamięć kontynuacji nadal działa, ponieważ nie jest używany w systemie operacyjnym, a tym samym unieważnia wskaźnik, który jest następnie odpowiedzialny za dostęp do pamięci poza jego zasięg. Czy to założenie jest poprawne? Czy mogę jakoś tego uniknąć lub czy jest to błąd w dopalaniu?

Edit 2: Poniżej znajduje się minimalny przykład tworzenie problemu:

#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"; 
    } 
}; 

I dodał dwa screeny wziąłem w Xcode pokazać sytuację w przyszłości, w której conitnuation pracuje i wydaje że Mankarnas (w komentarzach) i ja (powyżej) są poprawne: Wydaje się, że część pamięci, w której przechowywana jest kontynuacja, zostaje uwolniona i dlatego pojawia się niezdefiniowane zachowanie.

Jest to sytuacja przed get() nazywa się: Situation before <code>get</code> is called

Jest to sytuacja po get() nazwano: Situation after <code>get</code> was called

Adres px wskazuje jest 0x00 później.

+0

czy sprawdziłeś 'onError'? – inf

+0

Co masz na myśli? Że zawiera błędny kod? Składa się z 'std :: cout <<" foo ";' i działa, jeśli umieściłem wywołanie 'onError' przed wywołaniem' get() 'przyszłości. – Stephan

+0

Czy 'listener.get()' ma wartość inną niż null przed linią, która ulega awarii? (Nie mogę odtworzyć problemu lokalnie, prawdopodobnie byłby przydatny, gdybyś mógł skonstruować kompletną wersję testową, która eksponuje problem dla ciebie, więc nie muszę zgadywać na temat części, których nie opisałeś). – Mankarse

Odpowiedz

2

Otworzyłem bilet na ulepszenie 1.53 and it was confirmed jako błąd. Wygląda na to, że future.then nie jest jeszcze stabilny i dlatego nie jest gotowy do użycia produkcyjnego.Jedna rada stamtąd było wykorzystanie

#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET 

Ale to wyraźnie stwierdził, że ta funkcja nie jest jeszcze stabilny (a dokumentacja jest trochę brakuje tej informacji).

Mam teraz włączony, aby użyć osobnego wątku, w którym będę czekać na przyszłość i wykonać odpowiednie działania wtedy.

Powiązane problemy