2016-07-17 26 views
1

Ich habe das folgende Stück Code:Warum werden meine verketteten Methoden mit boost :: future nicht aufgerufen?

#define BOOST_THREAD_PROVIDES_FUTURE 
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION 

#include <iostream> 
#include <thread> 
#include <boost/thread/future.hpp> 

using namespace boost; 

int foo(boost::future<int> x) { 
    std::cout << "first stage(" << x.get() << ")" << '\n'; 
    return x.get(); 
} 

int main() 
{ 
    std::cout << "making promise" << '\n'; 
    boost::promise<int> p; 
    boost::future<int> f = p.get_future(); 
    std::cout << "future chain made" << '\n'; 
    std::thread t([&](){ 
    f.then(foo) 
     .then([](boost::future<int> x){ std::cout << "second stage " << 2 * x.get() << '\n'; return 2 * x.get(); }) 
     .then([](boost::future<int> x){ std::cout << "final stage " << 10 * x.get() << '\n'; }); 
    }); 

    std::cout << "fulfilling promise" << '\n'; 
    p.set_value(42); 
    std::cout << "promise fulfilled" << '\n'; 

    t.join(); 
} 

und ich kompilieren es etwa so:

g++ -g -Wall -std=c++14 -DBOOST_THREAD_VERSION=4 main.cpp -lboost_thread -lboost_system -pthread 

und ich bekomme die folgende Ausgabe:

making promise 
future chain made 
fulfilling promise 
promise fulfilled 
first stage(42) 

Warum meine 2 lambdas gekettet im Thread t nicht aufgerufen? Fehle ich etwas?

Ich habe versucht, boost::future::get() Gespräch hinzugefügt wird, aber ich erhalte eine Ausnahme dann:

std::cout << "fulfilling promise" << '\n'; 
    p.set_value(42); 
    std::cout << "promise fulfilled" << '\n'; 

    std::cout << "value " << f.get() << '\n'; 

    t.join(); 

Fehler:

making promise 
future chain made 
fulfilling promise 
promise fulfilled 
first stage(42) 
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::future_uninitialized> >' 
    what(): Operation not permitted on an object without an associated state. 
[1] 20875 abort  ./main 

I boost bin mit 1.58.0 und gcc 5.4.0

Online Quelllink (mit booost 1.58.0 und gcc 5.3.0) http://melpon.org/wandbox/permlink/G8rqt2eHUwI4nzz8

Antwort

1

Wie ein großer Dichter einst schrieb, "warte darauf".

std::thread t([&](){ 
    f.then(foo) 
    .then([](boost::shared_future<int> x){ std::cout << "second stage " << 2 * x.get() << '\n'; return 2 * x.get(); }) 
    .then([](boost::shared_future<int> x){ std::cout << "final stage " << 10 * x.get() << '\n'; }) 
    .get(); 
}); 

Der Thread tut nichts, aber eine Kette von Futures einrichten. Es läuft keiner von ihnen.

Sie starten die Kette (mit Ihrem Set), und Sie warten auf die Kette eingerichtet (mit Join), aber Hauptausgänge vor der Kette abgeschlossen ist. Sie erhalten "Glück", mit einem vor dem Prozess verlassen.

Wirklich, Sie sollten die Kette im Haupt-Thread einrichten und warten auf die letzte Zukunft von der Kette in Ihrem Thread t. Dann macht dein Code mehr Sinn.

auto last = f.then(foo) 
    .then([](boost::shared_future<int> x){ std::cout << "second stage " << 2 * x.get() << '\n'; return 2 * x.get(); }) 
    .then([](boost::shared_future<int> x){ std::cout << "final stage " << 10 * x.get() << '\n'; }); 

std::thread t([&](){ 
    last.get(); 
}); 

Dies unterstreicht die Tatsache, dass der Faden t nicht einen nützlichen Zweck dient: ersetzen t.join() mit last.get() im Hauptthread und die Variable t vollständig löschen.

Wie unten in den Kommentaren erwähnt, rufen Sie auch get zweimal: Damit das funktioniert, benötigen Sie eine shared_future. Das ist wahrscheinlich der Grund, warum dein Glück konsistent ist, da der zweite die Threads blockieren kann.

+0

Mit 'std :: future' ist es illegal,' get() 'mehr als einmal aufzurufen; gilt das auch für 'boost :: future'? (Die Behauptung, die ich beim Ausführen bekomme, legt dies nahe, aber die Dokumentation macht es mir nicht klar ...) – ildjarn

+0

@Yakk Du hast Recht, aber wir beide haben einen sehr wichtigen Punkt in meinem Code verpasst: Ich rief an x.get() 'in Callbacks zweimal, das ist UB. – Patryk

+0

@pat faltete das ein. Wenn sie 'std' waren, machte die implizite Umwandlung in die gemeinsame Zukunft von rvalue future die Fixierung einfach: Angenommen, Boost ist so intelligent. – Yakk