std :: asyncメソッドにタイムアウトを実装する方法はありますか?そのため、スレッドが指定された時間完了しなかった場合に、この呼び出しをタイムアウトして完了させたいと思います。この機能を実装するにはどうすればよいですか。
2 に答える
この標準は、非協力的にスレッドを強制終了する方法を提供していません。自動タイムアウト機能の欠如は、このもう1つの例です。
std::async
代わりに、これを協調的に処理するために渡すコードを実装する必要があります。スレッドを協調的に強制終了するための1つのパターンは、非同期関数を続行するかどうかをチェックするメソッドを提供するオブジェクトを関数に渡すことです。続行しない場合は、例外をスローします。
struct Time_out {
std::chrono::steady_clock start = std::chrono::steady_clock::now();
std::chrono::milliseconds timeout;
Time_out(std::chrono::milliseconds t) : timeout(t) {}
void check() {
if (start + timeout < std::chrono::steady_clock::now())
throw timeout_exception();
}
};
std::future<void> f = std::async([](Time_out t) {
while(more work) {
// do work
t.check();
}
}, Time_out(std::chrono::seconds(2));
f.get();
スレッドに到達してそれを強制終了する(標準の)方法はありません。とにかく、これは一般的に悪い考えです。よりクリーンなオプションは、開始時間と最大期間を関数に渡してから(計算の進行中に複数回)、現在の時間から開始時間を引いた時間が長すぎるかどうかを確認することです。
私はこのようなものを作ります:
#include <chrono>
template <typename Clock = std::chrono::steady_clock>
class timeout
{
public:
typedef Clock clock_type;
typedef typename clock_type::time_point time_point;
typedef typename clock_type::duration duration;
explicit timeout(duration maxDuration) :
mStartTime(clock_type::now()),
mMaxDuration(maxDuration)
{}
time_point start_time() const
{
return mStartTime;
}
duration max_duration() const
{
return mMaxDuration;
}
bool is_expired() const
{
const auto endTime = clock_type::now();
return (endTime - start_time()) > max_duration();
}
static timeout infinity()
{
return timeout(duration::max());
}
private:
time_point mStartTime;
duration mMaxDuration;
};
この単純なユーティリティは、開始時間と最大期間を追跡し(そして無限大を指定する方法を提供し)、ユーザーが単純な事実、最も重要なのはタイムアウトが発生したかどうかを照会できるようにします。
以下でテストします。定義/未定義によって偽の遅延を追加できますFAKE_DELAY
:
#include <iostream>
#include <future>
#define FAKE_DELAY
void fake_delay()
{
#ifdef FAKE_DELAY
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
#endif
}
void short_running_function(timeout<> timelimit)
{
fake_delay();
if (timelimit.is_expired())
std::cout << "short running thread ran out of time" << std::endl;
else
std::cout << "short running function finished" << std::endl;
}
void long_running_function(timeout<> timelimit)
{
for (unsigned i = 0; i < 10; ++i) {
if (timelimit.is_expired())
{
std::cout << "long running thread ran out of time" << std::endl;
return;
}
std::cout << "long running thread doing work" << std::endl;
fake_delay();
}
std::cout << "long running function finished" << std::endl;
}
int main()
{
std::async(short_running_function,
timeout<>(std::chrono::milliseconds(500))).wait();
std::async(short_running_function,
timeout<>(std::chrono::milliseconds(5000))).wait();
std::async(long_running_function,
timeout<>(std::chrono::milliseconds(500))).wait();
std::async(long_running_function,
timeout<>(std::chrono::milliseconds(5000))).wait();
std::async(long_running_function,
timeout<>::infinity()).wait();
}
FAKE_DELAY
オフの場合の1つの可能な出力:
ショートランニング機能終了
ショートランニング機能終了
ロングランニングスレッド作業
ロングランニングスレッド作業
ロングランニングスレッド作業
ロングランニングスレッド作業
ロングランニングスレッド作業ロングランニングスレッド
作業
ロングランニングスレッド作業
ロングランニングスレッド作業
ロングランニングスレッド実行中
長時間実行中スレッド実行中
長時間実行中関数終了
長時間実行中スレッド実行中
長時間実行中スレッド実行中
長時間実行中スレッド実行中
長時間実行中スレッド実行中
長時間実行中スレッド実行中作業中
長時間のスレッドの実行長時間のスレッド
の実行長時間のスレッドの実行
長時間のスレッドの実行長時間のスレッドの実行長時間の
スレッド
の実行
長時間の実行機能の終了
長時間のスレッドの実行
長時間のスレッドの実行長時間のスレッド
の実行長時間のスレッドの実行 長時間
のスレッドの実行
実行中のスレッド実行中のスレッド実行中のスレッド
実行中の実行中のスレッド実行中の実行中のスレッド
実行中のスレッド実行中のスレッド
実行中の
スレッド実行中のスレッド実行中の
スレッド
実行中の実行関数終了
FAKE_DELAY
onで可能な出力の1つ:
短時間のスレッドが時間切れになりました
短時間の実行機能が終了しました
長時間
のスレッドが動作します長時間のスレッドが動作しなくなりました長時間のスレッドが動作します長時間のスレッドが動作します長時間のスレッドが動作します長時間のスレッドが動作します長時間の
スレッド
が動作し
ます
長時間
実行し
ますスレッドが時間切れになっている長時間実行され ているスレッド
作業を実行して いる長時間 実行されている スレッド 作業を実行している長時間実行されているスレッド実行中のスレッド実行中のスレッド実行中のスレッド実行中のスレッド実行中のスレッド実行中のスレッド実行中のスレッド実行中の スレッド実行中の スレッド
長時間実行中のスレッド作業中
長時間実行中のスレッド作業中
長時間実行機能が終了しました