1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
   | #include <iostream>
#include <future>
#include <chrono>
#include <tuple>
#include <type_traits>
#include <string>
 
namespace tupleit {
	// utilitaires pour la manipulation de tuple
	template<std::size_t I = 0, typename FuncT, typename... Tp>
	inline typename std::enable_if<I == sizeof...(Tp), void>::type
	for_each(std::tuple<Tp...>&, FuncT)
	{ }
 
	template<std::size_t I = 0, typename FuncT, typename... Tp>
	inline typename std::enable_if < I <sizeof...(Tp), void>::type
	for_each(std::tuple<Tp...>& t, FuncT f)
	{
		f(std::get<I>(t));
		for_each < I + 1 > (t, f);
	}
}
 
struct Cin 
{
	template <typename T>
	void operator()(T& t) {
		std::cin >> t;
	}
};
 
template <typename... Args>
class asyncin {
	std::future<void> ftr;
	std::tuple<Args...> ret;
public:
	asyncin() : ftr(std::async(std::launch::async, [this]() {
            tupleit::for_each(ret, Cin());
	}))
	{}
 
	template< class Rep, class Period >
	std::future_status  wait_for(const std::chrono::duration<Rep,Period>& timeout_duration) const {
		return ftr.wait_for(timeout_duration);
	}
 
	// fonction bloquante
	void get(Args&... args) const {
		ftr.wait();
		std::tie(args...) = ret; // todo : copy -> move
	}
 
};
 
int main()
{
	// entree asynchrone de myint et mystr
	int myint{};
	std::string mystr{};
	asyncin<int, std::string> acin{};
 
	// ... pendant un traitement quelconque ...
	for(auto i : {1, 2, 3, 4, 5, 6, 7 ,8 ,9}) {
		std::cout << i;
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
 
	// On attend myint et mystr
	if(std::future_status::ready == acin.wait_for(std::chrono::seconds(1))) {
		if(std::cin.good()) {
			acin.get(myint, mystr);
			std::cout << std::endl << "(Myint, Mystr) = (" << myint << ", " << mystr << ")";
		} 
		else {
			std::cout << std::endl << "Bad input" << std::endl;
			std::cin.clear();
		}
	}
	else {
		std::cout << "Timeout ! " << std::endl;
		// On ne peut pas annuler l'operation asynchrone en std C++11 (tuer le thread)
		// On a le choix :
		//  - reboucler et attendre indefiniment le thread 
		// OU
		//  - recuperer std::thread::native_handle et tuer le thread avec l'API native 
		//	  dans le destructeur de asyncin par exemple qui se chargerait de nettoyer egalement le buffer de cin.
	}
    return 0;
} | 
Partager