在 c++11 中,如何实现一个程序,该程序执行两个相同类型的昂贵(网络)调用,然后只等待较快的结果,而不是等待和丢弃较慢的结果。std::thread 不能被中断并且不返回方便的 std::future。并且返回未来的 std::async 既不能中断也不能分离。
两个主要问题是: - 更快结果到达时的通知。- 终止(和清理)较慢的线程。
NoSenseEtAl 提供了以下链接:
http://fpcomplete.com/functional-patterns-in-c/
Bartosz 提供了一些非常通用的可组合异步 API 的示例代码。我无耻地将其剥离为仅我需要(并且可以理解)的内容。只是“异步或组合器”:
#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();
}
您必须使用操作系统提供的工具来发出“真正的”异步操作,这些操作在完成时会发送某种形式的通知。通常此类操作可以在完成之前终止;如果他们不能,您将不得不找到另一种机制,或者只是让他们完成并忽略结果。