c++11 では、同じタイプの 2 つの高価な (ネットワーク) 呼び出しを実行し、遅い方の結果を待って破棄するのではなく、速い方の結果のみを待つプログラムを実装するにはどうすればよいでしょうか。std::thread は中断できず、便利な std::future を返しません。また、未来を返す std::async は、中断することも切り離すこともできません。
2 つの主な問題は次のとおりです。 - より迅速な結果が到着したときの通知。- 遅いスレッドの終了 (およびクリーンアップ)。
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();
}
オペレーティングシステムが提供する機能を使用して、完了時に何らかの形式の通知を送信する「真の」非同期操作を発行する必要があります。多くの場合、このような操作は完了する前に終了できます。それらが見つからない場合は、別のメカニズムを見つけるか、単にそれらを完了させて結果を無視する必要があります。