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