【C++11～】タイムアウト機能付きメンバ関数


# 仕様

　こんな関数を作りたい

|処理結果|is_timeout|返り値|
|---|---|---|
|成功|false|true|
|失敗|false|false|
|タイムアウト|true|false|

　特に組み込み系の設計では、数行程度でポーリング処理を単純化して書けるので、あると超便利である。

# 方針

- クラス"SubFunction"の中に、クラスSourceClass1, SourceClass2のオブジェクトを生成する

 - テンプレートを使って、双方のクラスの参照を許可する

 - 補足：生成せずに参照する場合は、SubFunctionコンストラクタを見直す

- 内部処理は、std::asyncで記述して関数の入力／返り値の対応関係の見通しを良くして記載する。

 - 補足：wait_forを使用しなければ非同期

- タイムアウトかどうかを判定するのは、std::futureの返り値を使用する。

# ソースコード

```C++:SourceClass.h

#pragma once

namespace Timeout {
	class SourceClass1 {
	public:
		SourceClass1() {
			
		}

		virtual ~SourceClass1() {
			
		}
	};

	class SourceClass2 {
	public:
		SourceClass2() {

		}

		virtual ~SourceClass2() {

		}
	};
}


```

```C++: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);
	};

}




```


```C++: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;
}

```


```C++: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
```