В c ++ 11 как можно реализовать программу, которая выполняет два дорогостоящих (сетевых) вызова одного и того же типа, а затем ожидает только результат от более быстрого, не ожидая и не отбрасывая более медленный результат. std :: thread не может быть прерван и не возвращает удобного std :: future. И std :: async, который возвращает будущее, не может быть ни прерван, ни отсоединен.
Два основных вопроса:
Уведомление о получении более быстрого результата.
— Уничтожение (и очистка) более медленного потока.
NoSenseEtAl предоставил ссылку на:
http://fpcomplete.com/functional-patterns-in-c/
Там Bartosz предоставляет пример кода некоторых очень универсальных составных асинхронных API. Я беззастенчиво разобрал его до того, что мне было нужно (и смог понять). Просто «Async Or-Combinator»:
#include <functional>
#include <iostream>
#include <string>
#include <memory>
#include <algorithm>
#include <ctype.h>
#include <thread>
#include <mutex>
#include <chrono>
#include <random>
using namespace std;
//--------
// Helpers
//--------
void tick(int n)
{
for(int i = 0; i < n; ++i)
{
cout << i << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
//-------
// Async
//-------
template<class A>
struct Async {
virtual ~Async() {}
virtual void andThen(function<void(A)>) = 0;
};
//-------
// Monoid
//-------
template<class A>
struct Mplus : Async<A>
{
Mplus(unique_ptr<Async<A>> asnc1, unique_ptr<Async<A>> asnc2)
: _asnc1(move(asnc1)), _asnc2(move(asnc2)), _done(false)
{}
~Mplus() {}
void andThen(function<void(A)> k)
{
_asnc1->andThen([this, k](A a)
{
lock_guard<mutex> l(_mtx);
if (!_done)
{
_done = true;
k(a);
}
});
_asnc2->andThen([this, k](A a)
{
lock_guard<mutex> l(_mtx);
if (!_done)
{
_done = true;
k(a);
}
});
}
unique_ptr<Async<A>> _asnc1;
unique_ptr<Async<A>> _asnc2;
bool _done;
mutex _mtx;
};
template<class A>
unique_ptr<Async<A>> mplus(unique_ptr<Async<A>> asnc1, unique_ptr<Async<A>> asnc2)
{
return unique_ptr<Async<A>>(new Mplus<A>(move(asnc1), move(asnc2)));
}
//----------------
// Fake async APIs
//----------------
void getStringAsync(string s, function<void(string)> handler)
{
thread th([s, handler]()
{
cout << "Started async\n";
size_t sleep = rand () % 10;
this_thread::sleep_for(chrono::seconds(sleep));
handler("Done async: " + s);
});
th.detach();
}
struct AsyncString : Async<string>
{
AsyncString(string s) : _s(s) {}
void andThen(function<void(string)> k)
{
getStringAsync(_s, k);
}
string _s;
};
unique_ptr<Async<string>> asyncString(string s)
{
return unique_ptr<Async<string>>(new AsyncString(s));
}
void testOr()
{
// Test or combinator / mplus
auto or = mplus<string>(asyncString(" Result One "), asyncString(" Result Two "));
or->andThen([](string s)
{
cout << "Or returned : " << s << endl;
});
tick(10);
}
void main()
{
srand ( time(NULL) );
testOr();
}
Вы должны использовать средства, предоставляемые операционной системой, для выдачи «истинно» асинхронных операций, которые отправляют уведомления в той или иной форме по завершении. Часто такие операции могут быть прекращены до завершения; если они не могут, вам нужно будет найти другой механизм, или просто дайте им завершить и проигнорируйте результат.