仕様
こんな関数を作りたい
処理結果 | is_timeout | 返り値 |
---|---|---|
成功 | false | true |
失敗 | false | false |
タイムアウト | true | false |
特に組み込み系の設計では、数行程度でポーリング処理を単純化して書けるので、あると超便利である。
方針
-
クラス"SubFunction"の中に、クラスSourceClass1, SourceClass2のオブジェクトを生成する
-
テンプレートを使って、双方のクラスの参照を許可する
-
補足:生成せずに参照する場合は、SubFunctionコンストラクタを見直す
-
内部処理は、std::asyncで記述して関数の入力/返り値の対応関係の見通しを良くして記載する。
-
補足:wait_forを使用しなければ非同期
-
タイムアウトかどうかを判定するのは、std::futureの返り値を使用する。
ソースコード
SourceClass.h
#pragma once
namespace Timeout {
class SourceClass1 {
public:
SourceClass1() {
}
virtual ~SourceClass1() {
}
};
class SourceClass2 {
public:
SourceClass2() {
}
virtual ~SourceClass2() {
}
};
}
SubFunction.h
#pragma once
#include <chrono>
#include <functional>
namespace Timeout {
template <typename Target>
class SubFunction {
private:
Target* _target;
public:
SubFunction();
virtual bool WaitForRunning(std::function<bool(Target*, bool&)> wait_func, std::chrono::milliseconds duration, bool& is_timeout);
private:
bool _WaitForRunning(std::function<bool(bool&)> func,std::chrono::milliseconds duration, bool& is_timeout);
};
}
SubFunction.cpp
#include <future>
#include "SubFunction.h"
#include "SourceClass1.h"
#include "SourceClass2.h"
using namespace Timeout;
SubFunction<SourceClass1>::SubFunction() {
_target = new SourceClass1();
}
SubFunction<SourceClass2>::SubFunction() {
_target = new SourceClass2();
}
bool SubFunction<SourceClass1>::WaitForRunning(std::function<bool(SourceClass1*, bool&)> wait_func, std::chrono::milliseconds duration, bool& is_timeout) {
auto func_internal = [this, &wait_func] (bool& is_done) {
return wait_func(_target, is_done);
};
return _WaitForRunning(func_internal, duration, is_timeout);
}
bool SubFunction<SourceClass2>::WaitForRunning(std::function<bool(SourceClass2*, bool&)> wait_func, std::chrono::milliseconds duration, bool& is_timeout) {
auto func_internal = [this, &wait_func] (bool &is_done) {
return wait_func(_target, is_done);
};
return _WaitForRunning(func_internal, duration, is_timeout);
}
template <typename Target>
bool SubFunction<Target>::_WaitForRunning(std::function<bool(bool&)> func, std::chrono::milliseconds duration, bool& is_timeout) {
is_timeout = false;
bool is_succeed = false;
bool is_done = false;
// ラムダ式で処理を実行
// 終了したらis_doneをtrueにする
std::future<bool> future_wait = std::async(std::launch::async, [this, func, &is_timeout, &is_succeed, &is_done]() {
while (!is_timeout && !is_done) {
is_succeed = func( is_done);
}
return is_done;
});
// ポーリング
auto timeout_status = future_wait.wait_for(duration);
// タイムアウト
if (timeout_status == std::future_status::timeout) {
is_timeout = true;
return false;
} else {
return is_succeed;
}
return true;
}
main.cpp
#include <windows.h>
#include <iostream>
#include "SourceClass1.h"
#include "SubFunction.h"
int main() {
auto subfunc_obj = new Timeout::SubFunction<Timeout::SourceClass1>();
// 成功する場合
bool is_timeout;
if( subfunc_obj->WaitForRunning([](Timeout::SourceClass1* source, bool &is_done) {
is_done = true;
return true;
}, std::chrono::milliseconds(3000), is_timeout) ) {
std::cout << "Success" << std::endl;
} else {
std::cout << "Failed" << std::endl;
if( is_timeout) {
std::cout << "Timeout" << std::endl;
}
}
// 失敗する場合
if (subfunc_obj->WaitForRunning([](Timeout::SourceClass1* source, bool& is_done) {
is_done = true;
return false;
}, std::chrono::milliseconds(3000), is_timeout)) {
std::cout << "Success" << std::endl;
} else {
std::cout << "Failed" << std::endl;
if (is_timeout) {
std::cout << "Timeout" << std::endl;
}
}
// タイムアウト
if (subfunc_obj->WaitForRunning([](Timeout::SourceClass1* source, bool& is_done) {
Sleep(4000); // ** Windows.h固有コード. gccならばsys/time.hのsleep ** //
return true;
}, std::chrono::milliseconds(3000), is_timeout)) {
std::cout << "Success" << std::endl;
} else {
std::cout << "Failed" << std::endl;
if (is_timeout) {
std::cout << "Timeout" << std::endl;
}
}
return 0;
}
結果
Success
Failed
Failed
Timeout