2013-02-12 9 views
5

Sto sviluppando per iOS in XCode 4.6. Sto scrivendo una libreria per un servizio e uso boost per avviare i thread. Uno dei miei metodi si presenta così:Accesso non valido in boost :: future <>. Then() dopo l'accesso a date future

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

Quando si esegue questo sul dispositivo ottengo una EXC_BAD_ACCESS alla linea marcata. Sono molto sorpreso da questo, dal momento che la prima chiamata a onConnected ha esito positivo e anche se aggiungo una chiamata onError prima del if anche quella funziona.

Essendo abbastanza inesperto con C++, sarei felice di ogni informazione su quale sia la ragione, su come eseguirne il debug e su come essere consapevole di questo problema la prossima volta. Inoltre non sono abbastanza sicuro di quali informazioni siano rilevanti. Quello che ho capito può essere rilevante da quello che ho trovato finora là fuori, il seguente potrebbe: ResultListener e Service sono boost::noncopyable. Ho controllato il conteggio dei riferimenti dello shared_ptr (usando use_count) e aumenta nel seguito. Sto usando boost 1.53. Il metodo viene chiamato in questo modo

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

foo essere una semplice classe che non fa altro che stampare su std::cout se un metodo viene chiamato.

Edit: Ulteriori curiosare in giro mi permetta di ispezionare la chiamata get() e ho trovato il seguente codice nel future.hpp in esecuzione:

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

Credo che questo sia il problema. La chiamata a reset() sembra liberare la memoria dello future_shared_ptr. La mia ipotesi è, questo segna la memoria la continuazione è ancora in esecuzione in quanto non utilizzato per il sistema operativo e quindi invalida il puntatore listener che viene quindi caugt come accesso alla memoria al di fuori del suo ambito. Questa supposizione è corretta? Posso in qualche modo evitare questo o è un bug in boost?

Edit 2: Il seguente è un esempio minimo creando il problema:

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

ho aggiunto due screenshot presi in XCode per mostrare la situazione nel futuro in cui la conitnuation è in esecuzione e sembra che Mankarnas (nei commenti) e me (sopra) sono corretti: sembra che la parte di memoria in cui è archiviata la continuazione sia liberata e quindi si verifichi un comportamento indefinito.

Questa è la situazione prima get() si chiama: Situation before <code>get</code> is called

Questa è la situazione dopo get() è stato chiamato: Situation after <code>get</code> was called

L'indirizzo px indica è 0x00 dopo.

+0

hai controllato "onError'? – inf

+0

Cosa intendevi? Che contiene codice errato? Consiste di 'std :: cout <<" foo ";' e funziona se metto la chiamata a 'onError' prima della chiamata 'get()' del futuro. – Stephan

+0

È 'listener.get()' non null prima della riga che si blocca? (Non riesco a riprodurre il problema localmente, sarebbe probabilmente utile se tu potessi costruire una prova _complete_ che presenta il problema per te, quindi non devo indovinare le parti che non hai descritto). – Mankarse

risposta

2

Ho aperto un ticket contro boost 1.53 and it was confirmed come bug. Sembra che future.then non sia ancora stabile e quindi non sia pronto per l'uso di produzione.Un consiglio da lì è stato quello di utilizzare

#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET 

Ma è stato chiaramente affermato che questa funzione non è ancora stabile (e che la documentazione è carente questo po 'di informazioni).

Sono passato ora per utilizzare un thread separato in cui attenderò il futuro ed eseguirò le azioni appropriate.

Problemi correlati