C++ 两个相同的(网络)呼叫。如何等待最快的,放弃最慢的?

C++ 两个相同的(网络)呼叫。如何等待最快的,放弃最慢的?,c++,c++11,stdthread,C++,C++11,Stdthread,在c++11中,如何实现一个程序,该程序执行两个相同类型的昂贵网络调用,然后只等待较快的结果,而不等待并丢弃较慢的结果。线程不能被中断,并且不会返回方便的std::future。返回未来的std::async既不能中断也不能分离 两个主要问题是: -当更快的结果到达时通知。 -终止和清理较慢的线程。您必须使用操作系统提供的功能来发出真正的异步操作,这些操作完成后会发送某种形式的通知。通常,此类作业可在完工前终止;如果他们不能,你必须找到另一种机制,或者干脆让他们完成并忽略结果。Nosenseal

在c++11中,如何实现一个程序,该程序执行两个相同类型的昂贵网络调用,然后只等待较快的结果,而不等待并丢弃较慢的结果。线程不能被中断,并且不会返回方便的std::future。返回未来的std::async既不能中断也不能分离

两个主要问题是: -当更快的结果到达时通知。
-终止和清理较慢的线程。

您必须使用操作系统提供的功能来发出真正的异步操作,这些操作完成后会发送某种形式的通知。通常,此类作业可在完工前终止;如果他们不能,你必须找到另一种机制,或者干脆让他们完成并忽略结果。

Nosenseal提供了以下链接:

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();
}

使用非阻塞套接字并选择非阻塞文件描述符。当你收到第一个结果时,你可以同时关闭这两个程序。中断一个程序是不自然的。解决方案取决于具体的细节,你必须设计一个程序,以便它可以被有意义地中断;对于异步编程,您应该使用类似的东西。您确定这是对一个经过良好测试、文档丰富的库的改进吗?该库已经被成千上万的人使用,比如前面提到的Boost.ASIO?@ildjarn Boost::ASIO看起来不错,但是很大。我只是担心学习所需的时间,特别是如果我需要扩展它来实际解决我的具体问题。它有类似于这种类型的异步或组合器吗?ASIO是的一个实现。boostcon2010中的一些优秀幻灯片展示了模式/库的高级设计,可以在这里找到:我很高兴你发现这个链接很有趣。我在视频3的开头停了下来,因为我最近很忙顺便说一句,如果您最终使用了代码,请用结果和经验更新您的答案。@Ghita:多个异步读取,例如,使用同一个处理程序的异步读取,其中处理程序取消除第一个要处理的操作以外的所有活动操作。原子学和共享ptr使这变得微不足道。