2017-03-20 10 views
2

boost::asio::io_serviceから戻り値を取得するにはどうすればよいですか?関数の書き換えを伴わないバインドや単純な構文を使用することは可能ですか?Boost :: ASIO:io_serviceから戻り値を取得するにはどうすればよいですか?

以下は最小の例です。私はGetSum()の値を取得しようとしています:

#include <iostream> 
#include <boost/asio.hpp> 
#include <functional> 

using namespace std; 

void SayHello() 
{ 
    std::cout<<"Hello!"<<std::endl; 
} 

template <typename T> 
T GetSum(T a, T b) 
{ 
    std::cout<<"Adding " << a << " and " << b << std::endl; 
    return a+b; 
} 

int main(int argc, char *argv[]) 
{ 
    boost::asio::io_service ioservice; 

    ioservice.post(&SayHello); 
    ioservice.post(std::bind(&GetSum<double>,1,2)); 

    ioservice.run(); 
    return 0; 
} 

なぜですか?私はスレッドプールを用意しているので、ユーザが自分の関数の戻り値を取得することを可能にするためのオプションを考えています。 。

私のソリューション:

int main(int argc, char *argv[]) 
{ 
    boost::asio::io_service ioservice; 

    ioservice.post(&SayHello); 
    double sum; 
    ioservice.post([&sum]() 
    { 
     sum = GetSum(1,2); 
    }); 

    ioservice.run(); 
    std::cout<< sum <<std::endl; //is 3 
    return 0; 
} 

しかし、私はまだ、バインド、または何かを持つシンプルな何かがあります願っています。

+1

あなたが – teivaz

+0

@teivazが右についてサウンズ[ 'のstd :: future'](http://en.cppreference.com/w/cpp/thread/future)のいくつかの種類を必要とするようだが、私思考未来は 'std :: thread'に対して明示的に行われます。これはスレッドライブラリの一部です。 –

+0

私はあなたのソリューションに加えて、操作が終了したときにio_serviceの内部で設定されている何らかの種類の 'ManualResetEvent'(またはmutex + cv)も取得すると思います。これにより、サブミッターは操作の結果を待つことができます( 'ioservice.run()'と同じように、キューに入れられたすべての操作が完了するまで待つだけでなく) 'std/boost :: future'を返します。 – Matthias247

答えて

1

私は提案からインスピレーションを得た解決策を考え出しましたstd::futureのようなものを使用してください。だから私はstd::futureを使用し、コードが動作します。

私がしたことは、単純にio_serviceから継承し、戻り値の将来を持つ新しいメソッドpost_with_futureを作成します。私はこのソリューションを改善するためにそれを批評していただければ幸いです。

#include <iostream> 
#include <functional> 
#include <type_traits> 
#include <future> 
#include <boost/asio.hpp> 

class future_io_service : public boost::asio::io_service 
{ 
public: 
    template <typename FuncType> 
    std::future<typename std::result_of<FuncType()>::type> post_with_future(FuncType&& func) 
    { 
     //keep in mind that std::result_of is std::invoke_result in C++17 
     typedef typename std::result_of<FuncType()>::type return_type; 
     typedef typename std::packaged_task<return_type()> task_type; 
     //since post requires that the functions in it are copy-constructible, we use a shared pointer for the packaged_task since it's only movable and non-copyable 
     std::shared_ptr<task_type> task = std::make_shared<task_type>(std::move(func)); 
     std::future<return_type> returned_future = task->get_future(); 
     this->post(std::bind(&task_type::operator(),task)); 
     return returned_future; 
    } 
}; 

void SayHello() 
{ 
    std::cout<<"Hello!"<<std::endl; 
} 

template <typename T> 
T GetSum(T a, T b) 
{ 
    std::cout<<"Adding " << a << " and " << b << std::endl; 
    return a+b; 
} 

int main() 
{ 
    future_io_service ioservice; 

    ioservice.post(&SayHello); 
    auto sum = ioservice.post_with_future(std::bind(&GetSum<int>,1,2)); 
    ioservice.run(); 
    std::cout<<sum.get()<<std::endl; //result is 3 
    return 0; 
} 
+0

ナー、これはいいですか?汚れている。このようなことをするには 'async_result'を使ってください。私の答えを見てください。 – Arunmu

+0

私は 'async_result'を使うつもりです。しかし、なぜこれが汚いのか聞いてもいいですか? –

+0

その言葉に違反しないでください:)私はそれが「ハック」であり、今までにio_serviceから派生した人は見かけませんでした。そして、あなたのユースケースはまったく必要ではありません。 – Arunmu

0

目標はまたあなたのための戻り値をキャプチャする機能のような単純な1つのライナーバインドを持っているのであれば、あなたはこのようにそれを実現することができます。

#include <iostream> 
#include <boost/asio.hpp> 
#include <functional> 

using namespace std; 

void SayHello() 
{ 
    std::cout<<"Hello!"<<std::endl; 
} 

template <typename T> 
T GetSum(T a, T b) 
{ 
    std::cout<<"Adding " << a << " and " << b << std::endl; 
    return a+b; 
} 

template<typename R, typename F, typename... Args> 
auto bind_return_value(R& r, F&& f, Args&&... args) 
{ 
    return [&]() 
    { 
     r = f(std::forward<Args>(args)...); 
    }; 
} 

int main(int argc, char *argv[]) 
{ 
    boost::asio::io_service ioservice; 

    ioservice.post(&SayHello); 
    double sum; 
    ioservice.post(bind_return_value(sum, &GetSum<double>, 1, 2)); 

    ioservice.run(); 
    std::cout<< sum <<std::endl; //is 3 
    return 0; 
} 
+0

答えをありがとう。実際に私はこのようなものを探していましたが、標準の一部として探していました。 –

+0

@TheQuantumPhysicist確かに、この答えは私には標準的なツールでしかできない結果ですが、誰かが新しい機能を実装せずにトリックを見つけるかもしれません:) – Drax

1

これは、あなたがasio::use_futureasync_resultを利用することによってそれを行うことができる方法です。値を渡し、和にハードコードされた引数を使用することで、この例を単純にしておきます。

#include <iostream> 
#include <thread> 
#include <asio.hpp> 
#include <asio/use_future.hpp> 

int get_sum(int a, int b) 
{ 
    return a + b; 
} 

template <typename Func, typename CompletionFunction> 
auto perform_asyncly(asio::io_service& ios, Func f, CompletionFunction cfun) 
{ 

    using handler_type = typename asio::handler_type 
         <CompletionFunction, void(asio::error_code, int)>::type; 

    handler_type handler{cfun}; 
    asio::async_result<handler_type> result(handler); 

    ios.post([handler, f]() mutable { 
     handler(asio::error_code{}, f(2, 2)); 
     }); 

    return result.get(); 
} 

int main() { 
    asio::io_service ios; 
    asio::io_service::work wrk{ios}; 
    std::thread t{[&]{ ios.run(); }}; 
    auto res = perform_asyncly(ios, get_sum, asio::use_future); 
    std::cout << res.get() << std::endl; 

    t.join(); 

    return 0; 
} 
+0

批判していないが、私が提示した例の条件を守っていない。呼び出しに 'get_sum'のパラメータを指定したことさえありません! 'use_future'と' async_result'について教えていただきありがとうございます。私はそれらについて研究するつもりです。 –

+1

はい、わかっています。私は本当にそれほど多くの努力を惜しみたくありませんでした。私は 'async_result'と' use_future'と呼ばれるものがあることを伝えたいと思います。 – Arunmu

関連する問題