2016-08-10 18 views
6

Biorąc pod uwagę następujący program testowy:asio 1.11.0 samodzielny wrap nie jest prawidłowy ... czy to ja?

#include <asio.hpp> 
#include <cassert> 

int main() 
{ 
    asio::io_service ios1, ios2; 
    asio::io_service::strand s2(ios2); 

    auto test_func = wrap(s2, [&] { 
     assert(s2.running_in_this_thread()); 
    }); 

    auto wrap_test_func = wrap(ios1, test_func); 

    wrap_test_func(); 

    ios1.run_one(); 
    ios2.run_one(); 

} 

moim rozumieniu jest to, że program ten nie powinien dochodzić.

wrap_test_func jest pakowany pod io_serviceios1. Funkcja, którą zawija, jest zawijana w strands2 (która używa ios2).

Jak rozumiem, wywołanie wrap_test_func powinno być równoważne z dispatch(ios1, test_func), które powinno następnie wysłać lambda w s2).

Wygląda jednak tak, jakby wrap odwijał wewnętrzne opakowanie.

Czy to oczekiwane zachowanie?

+0

nie jestem pewien jak to kompilowane, ponieważ nie znaleźliśmy żadnych funkcji globalnych oblewania. Używając zawijania na poziomie elementu, nie mogłem zobaczyć, jak to się dzieje, chociaż – Arunmu

+0

@Arunmu to nie jest boost :: asio. jest to samodzielna wersja 1.11.0 –

+0

Tak, nawet ja używam wersji samodzielnej 1.11.0 (tylko nagłówek). 'g ++ -std = C++ 11 -DASIO_STANDALONE -o wrap_test wrap_test.cc -I/Users/arunmu/asio-master/asio/include /' to sposób, w jaki go buduję. – Arunmu

Odpowiedz

5

Okazało się, że to było moje nieporozumienie.

Oto kopia post przez ASIO Autora:

Hi Richard,

Tak to zachowanie jest celowe. Jednak w sieci TS i najnowszy kod w gałęzi głównej ten obiekt został zmieniony na z wrap (co sugeruje dodanie kolejnej warstwy, zgodnie z oczekiwaniami) do bind_executor. Ta funkcja po prostu nakłada obiekt na wykonawcę powiązanego z ; jeśli już to miało, zostało ono nadpisane.

Jeśli potrzebujesz prawdziwego opakowanie to należy wyraźnie owinąć wewnętrzną obsługi w zewnętrznej obiektu funkcyjnego (lub lambda) i mają zewnętrzną uchwytu dispatch() wewnętrznej obsługi na swoim „związanego wykonawca”. Jak piszesz własną operację asynchroniczną, proponuję przyjęcie następujący wzór (udokumentowane w sieci TS w ramach „wymogów dotyczących operacji asynchronicznych” ):

  • Zadaj obsługi dla jego Associated executor za pomocą get_associated_executor.

  • post() program obsługi tego executora, jeśli operacja zakończy się natychmiast.

  • wywołanie() w przeciwnym razie należy wykonać program obsługi do tego executora.

Tak (kod niesprawdzone, mogą wymagać końcówki gałęzi master):

template<class Task, class Handler> 
    void async_execute(implementation& impl, Task&& task, Handler&& handler) 
    { 
     ... 

     auto ex = asio::get_associated_executor(handler get_io_context()); 

     // this is immediate completion, so we use post() 

     if (not impl) 
     { 
      post(ex, [handler = std::forward<Handler>(handler)]() mutable 
       { 
        promise_type promise; 
        promise.set_exception(std::make_exception_ptr(system_error(errors::null_handle))); 
        handler(promise.get_future()); 
       }); 
      return; 
     } 

     // this is not immediate completion, so we use dispatch() 
     // (NOTE: assumes this->post_execute() does not run the task) 

     // Optional. Really only needed if your io_context participates in the 
     // async operation in some way not shown in this snippet, and not 
     // simply as a channel for delivering the handler. 
     auto io_work = make_work_guard(get_io_contet()); 

     auto handler_work = make_work_guard(ex); 
     auto impl_ptr = impl.get(); 
     auto async_handler = [this, 
           ex, 
           impl_ptr, 
           io_work, handler_work, 
           handler = std::forward<Handler>(handler)] 
     (detail::long_running_task_op::identifier ident, 
     auto future) mutable 
     { 
      assert(impl_ptr); 
      io_work.reset(); 
      dispatch(ex, [handler = std::move(handler), future = std::move(future)]() mutable 
       { 
        handler(std::move(future)); 
       }); 
      assert(impl_ptr); 
      impl_ptr->remove_op(ident); 
     }; 

     ... 

     this->post_execute(); 
    } 

nadzieję, że to pomaga.

Pozdrawiam, Chris

+0

Czy to po prostu stało się bardziej skomplikowane? – Arunmu

+2

@Arunmu nie z perspektywy klienta. Dostawcy usług (jak ja) mają pewne nowe umiejętności do nauczenia się, ale zmiany są dobre - w szczególności możliwość przenoszenia obiektów typu "tylko ruch" do programów obsługi zakończenia (takich jak futures), co robię tutaj. –

Powiązane problemy