2012-01-24 16 views
1

多くのネットワーク機能を備えた多くのフリー機能を提供するexternライブラリを使用する必要があります。このライブラリは、残念ながら、非常にフェールセーフではなく、これらの関数のいくつかに永遠に(または少なくとも非常に長い時間)ぶつかってしまいます。これは私の選択肢ではないので、時間がかかりすぎると電話を中断したい。 C++: How to implement a timeout for an arbitrary function call?を見て、boost::lambdaライブラリを取るboost :: lambda :: bindを使用した任意の関数呼び出し

、私はこの思い付いた:

#include <iostream> 
#include <boost/thread/thread.hpp> 
#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 

int foo(int a, int b) { 
    boost::this_thread::sleep(boost::posix_time::seconds(2)); 
    return a+b; 
} 

int main() { 
    int ret; 
    boost::thread thrd(boost::lambda::var(ret) = boost::lambda::bind<int>(&foo, 1, 2)); 
    if(thrd.timed_join(boost::posix_time::seconds(1))) { 
     std::cout << ret << std::endl; 
    } 
    else { 
     std::cerr << "Function timed out." << std::endl; 
    } 
    return 0; 
} 

コンパイルと魔法のように動作します。しかし問題は、私はさまざまなパラメータと戻り値を持つたくさんの関数を持っており、すべてのケースで上記を書くことは退屈で冗長な作業のようです。

template <class t> t timeout(bindparam<t> &bind /* read below */, long sleep) { 
    t ret; 
    boost::thread thrd(boost::lambda::var(ret) = bind); 
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) { 
     return ret; 
    } 
    else throw std::runtime_error("timeout"); 
} 

アイデアは私が

try { 
    int ret = timeout<int>(boost::lambda::bind<int>(&foo, 1, 2), 500); 
    std::cout << ret << std::endl; 
} 
catch(std::runtime_error &e) { 
    std::cerr << e.what() << std::endl; 
} 

で重要な機能を実行することができるということですが、私はこれを行う方法が分からない、またはそれもあるかどうか:だから私は、関数の中でそれをラップしたいです可能。何とか私の関数に任意のboost::lambda::bindを渡すことはできますか?

更新:

示唆したように、私はboost::packaged_taskでそれを試してみました:

template <class T> T timeout(boost::packaged_task<T> &f, long sleep) { 
    T ret; 
    boost::thread thrd(boost::lambda::var(ret) = f); 
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) { 
     return ret; 
    } 
    else { 
     thrd.interrupt(); 
     throw std::runtime_error("timeout"); 
    } 
} 

をしかし、私はtimeout<int>(boost::packaged_task<int>(boost::bind(&foo, 1, 2)), 500);としてそれを使用しようとすると、私は奇妙なコンパイラエラーを取得:

main.cpp: In function ‘int main(int, char**)’: 
main.cpp:35: error: no matching function for call to ‘timeout(boost::packaged_task<int>, int)’ 

timeout(boost::packaged_task<int>, int)私のファンクションシグネチャはかなり正確ですtimeout(暗黙的に変換されるint部分を除く)私は間違って何をしていますか?

アップデート2:

私は最終的にそれが動作するようになったが、私はそれが信じられないほどのハード任意のドキュメントや例を見つけるために見つけたので、私は、私がやっていることは、それを行うための良い方法であるかどうかはわかりませんboost::packaged_taskにあり、基本的に私が扱ったのは、ライブラリのsource codeです。ここに私の仕事関数は次のとおりです。

template <class T> T timeout(boost::packaged_task<T> &f, long sleep) { 
    boost::thread thrd(boost::lambda::bind(&boost::packaged_task<T>::operator(), &f)); 
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) { 
     boost::unique_future<T> ret = f.get_future(); 
     return ret.get(); 
    } 
    thrd.interrupt(); 
    throw std::runtime_error("timeout"); 
} 

それはあなたがそれを使用するには、この道を行かなければならないという意味、一時では動作しない主な理由は、私は、それとは完全に満足していない:

try { 
    boost::packaged_task<int> f(boost::lambda::bind(&foo, 1, 2)); 
    int sum = timeout<int>(f, 500); 
    std::cout << sum << std::endl; 
} 
catch(std::runtime_error &e) { 
    std::cerr << e.what() << std::endl; 
} 

私は考えこれらの構造をもっと熟知している人がこれについてコメントすることができれば、まだとても幸せです。

+0

なぜ、 'boost :: packaged_task'を使用しないのですか? – Mankarse

+0

@Mankarse正直言って、聞いたことがないから。私はそれを調べるでしょう。ありがとう。 – nijansen

+0

@Mankarse boost :: packaged_taskで動作するようになった。ありがとう! – nijansen

答えて

1

これは機能しますか?

template <class T, class F> 
T timeout(const F &bind, long sleep) { 
    T ret; 
    boost::thread thrd(boost::lambda::var(ret) = bind); 
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) { 
     return ret; 
    } 
    else throw std::runtime_error("timeout"); 
} 
+0

この関数をどのように呼びますか? – nijansen

+0

関数がタイムアウトすると、動作は未定義です。スレッドは実行を継続し、最終的には 'ret'に値を格納しようとしますが、制御が' timeout'を去ると、 'ret'への参照はもはや有効になりません。 –

+0

@Rob Kennedyはい、スレッドは 'else'の場合に中断されるべきです。ありがとう。 – nijansen

関連する問題