23

引数の 1 つとしてタイムアウトを取る関数を C++ で作成する場合、タイムアウト引数自体にはどの型を使用すればよいですか?

このような関数の例は次のとおりです。

void my_function(bool work_really_hard, timeout_type timeout)
{
// Do stuff, until timeout is reached.
}

std::chrono::secondsforを使用することを考えtimeout_typeましたが、1 秒未満の領域でタイムアウトを使用することはできません。

代わりに使用する場合std::chrono::nanoseconds、たとえば 10 分を指定するのは面倒です。

関数の署名と呼び出しをきちんとシンプルに保ちながら、これを合理的な方法で解決する方法はありますか?

4

2 に答える 2

27

代わりに std::chrono::nanoseconds を使用する場合、たとえば 10 分と指定するのは面倒です。

実際、少なくとも面倒なことはありません。

#include <chrono>
#include <iostream>

void my_function(bool work_really_hard, std::chrono::nanoseconds timeout)
{
    std::cout << timeout.count() << '\n';
}

int main()
{
    my_function(true, std::chrono::minutes(10));
}

出力:

600000000000

問題が発生するのは、 , または(1/3 秒単位)など、nanosecondsに正確に変換されないものを渡したい場合だけです。nanosecondspicosecondsduration<long, ratio<1, 3>>

アップデート

私は、この回答が、(sehe による) 良い回答だと思った、既に受け入れられている回答の追加情報であることを意図していました。sehe はテンプレート化されたソリューションを推奨しましたが、これも問題ないと思います。

切り捨てたり丸めたりする必要がある可能性のあるものであっても、受け入れ たい場合は、seheの削除された回答を使用するのが方法です:std::chrono::duration

template <typename Rep, typename Period>
void my_function(bool work_really_hard, std::chrono::duration<Rep, Period> timeout)
{
    // Do stuff, until timeout is reached.
    std::this_thread::sleep_for(timeout);
}

何らかの理由でテンプレートを扱いたくない場合、および/または に正確に変換できる単位のみをクライアントに指定させることに満足している場合は、上で示したようにstd::chrono:nanoseconds使用std::chrono:nanosecondsすることも完全に受け入れられます。

すべてのstd::chrono「定義済み」単位:

hours
minutes
seconds
milliseconds
microseconds
nanoseconds

は暗黙的に に変換可能nanosecondsであり、切り捨てや丸めエラーは発生しません。2 本の明るい白線の範囲内に収まっている限り、オーバーフローは発生しません (自分の車線を維持することへのあいまいな言及)。期間が +/- 292 年以内であれば、これらの事前定義された単位でのオーバーフローを心配する必要はありません。

のような標準定義関数std::this_thread::sleep_forは、考えられるすべてのものと相互運用できるようにしたいという正確な理由で、sehe が示唆するようにテンプレート化されていますchrono:duration(たとえば、浮動小数点フェムト秒の 1/3)。独自の API にそれほどの柔軟性が必要かどうかを判断するのは、API 設計者次第です。

明確にする代わりに混乱させてしまったとしても、あまり心配しないでください。を使用することを選択した場合nanoseconds、切り捨てや丸めエラーなしで正確に機能するか、クライアントでコンパイル時エラーが発生します。実行時エラーは発生しません。

void my_function(bool work_really_hard, std::chrono::nanoseconds timeout)
{
    std::cout << timeout.count() << '\n';
}

int
main()
{
    using namespace std;
    using namespace std::chrono;
    typedef duration<double, pico> picoseconds;
    my_function(true, picoseconds(100000.25));
}

test.cpp:15:9: error: no matching function for call to 'my_function'
        my_function(true, picoseconds(100000.25));
        ^~~~~~~~~~~
test.cpp:4:10: note: candidate function not viable: no known conversion from 'duration<double, ratio<[...], 1000000000000>>' to
      'duration<long long, ratio<[...], 1000000000>>' for 2nd argument
    void my_function(bool work_really_hard, std::chrono::nanoseconds timeout)
         ^
1 error generated.

クライアントがコンパイル時エラーを受け取った場合、クライアントはいつでもduration_castそれを回避するために使用できます。

my_function(true, duration_cast<nanoseconds>(picoseconds(100000.25)));  // Ok

詳細については、次を参照してください。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm

この回答の上部にある元のコードを更新してください。C++1y では、C++14 を意味することを願っています。

using namespace std::literals;
my_function(true, 10min);  // also ok, is equal to 600000000000 nanoseconds

質問:「無限」のタイムアウトとして何をお勧めしますか (つまり、タイムアウトしないでください)。

私は最初に、タイムアウトを取らず、「タイムアウトしない」ことを意味する API を使用しようとしました。たとえばcondition_variable::wait。API を制御できれば、タイムアウトなしでそのような署名を作成できます。

それができない場合は、「大規模」なシリーズを作成しますchrono::durations

using days = std::chrono::duration
<
    std::int32_t, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
>;

using weeks = std::chrono::duration
<
    std::int32_t, std::ratio_multiply<days::period, std::ratio<7>>
>;

using years = std::chrono::duration
<
    std::int32_t, std::ratio_multiply<days::period, std::ratio<146097, 400>>
>;

using months = std::chrono::duration
<
    std::int32_t, std::ratio_divide<years::period, std::ratio<12>>
>;

次に、通話でこれらの長い期間のいずれかを使用します。たとえば、次のようになります。

std::this_thread::sleep_for(years(3));

push_things を最大限にしようとはしません (たとえば、OS が行った根本的な仮定を破る可能性があります)。途方もなく大きなもの (3 年など) を任意に選択するだけです。これはコード レビュー担当者の目を引き、有益な会話を開始する可能性があります。:-)

ビデオで利用できるようになりました: https://www.youtube.com/watch?v=P32hvk8b13M :-)

于 2013-11-15T20:12:15.453 に答える
1

タイムアウト タイプのテンプレート パラメーターを使用し、std::chronoタイプの 1 つ、または同様のインターフェイスを持つものを期待します。これにより、任意の時間単位で渡すことができます。

template<typename T>
void wait_a_while(const T& duration)
{
   std::this_thread::sleep(duration);
}

wait_a_while(boost::posix_time::seconds(5));
wait_a_while(std::chrono::milliseconds(30));
于 2013-11-15T19:56:18.553 に答える