52

高レベル
非同期モードで戻り値のないいくつかの関数を、関数が終了するのを待たずに呼び出したいと考えています。std::async を使用すると、将来のオブジェクトはタスクが終了するまで破棄されません。これにより、私の場合、呼び出しが同期されなくなります。

void sendMail(const std::string& address, const std::string& message)
{
    //sending the e-mail which takes some time...
}

myResonseType processRequest(args...)
{
    //Do some processing and valuate the address and the message...

    //Sending the e-mail async
    auto f = std::async(std::launch::async, sendMail, address, message);

    //returning the response ASAP to the client
    return myResponseType;

} //<-- I'm stuck here until the async call finish to allow f to be destructed.
  // gaining no benefit from the async call.

私の質問は

  1. この制限を克服する方法はありますか?
  2. (1) が「いいえ」の場合、これらの「ゾンビ」先物を受け取り、それらを待機するスレッドを一度実装する必要がありますか?
  3. (1) と (2) はいいえですか? 独自のスレッドプールを構築するだけの他のオプションはありますか?

注:
新しいスレッドの作成には回避したいオーバーヘッドがあるため、thread + detach(@galop1nが推奨)のオプションは使用しません。std::async を使用している間 (少なくとも MSVC では)、内部スレッド プールを使用しています。

ありがとう。

4

5 に答える 5

8

Future をグローバル オブジェクトに移動する(および未使用の Future の削除を手動で管理する) のではなく、実際に、非同期的に呼び出された関数のローカル スコープに移動することができます。

いわば、「非同期関数に独自の未来を持たせましょう」。

私は私のために働くこのテンプレートラッパーを思いつきました(Windowsでテスト済み):

#include <future>

template<class Function, class... Args>
void async_wrapper(Function&& f, Args&&... args, std::future<void>& future,
                   std::future<void>&& is_valid, std::promise<void>&& is_moved) {
    is_valid.wait(); // Wait until the return value of std::async is written to "future"
    auto our_future = std::move(future); // Move "future" to a local variable
    is_moved.set_value(); // Only now we can leave void_async in the main thread

    // This is also used by std::async so that member function pointers work transparently
    auto functor = std::bind(f, std::forward<Args>(args)...);
    functor();
}

template<class Function, class... Args> // This is what you call instead of std::async
void void_async(Function&& f, Args&&... args) {
    std::future<void> future; // This is for std::async return value
    // This is for our synchronization of moving "future" between threads
    std::promise<void> valid;
    std::promise<void> is_moved;
    auto valid_future = valid.get_future();
    auto moved_future = is_moved.get_future();

    // Here we pass "future" as a reference, so that async_wrapper
    // can later work with std::async's return value
    future = std::async(
        async_wrapper<Function, Args...>,
        std::forward<Function>(f), std::forward<Args>(args)...,
        std::ref(future), std::move(valid_future), std::move(is_moved)
    );
    valid.set_value(); // Unblock async_wrapper waiting for "future" to become valid
    moved_future.wait(); // Wait for "future" to actually be moved
}

async_wrapperを離れるまで、移動された未来のデストラクタがブロックされると思っていたので、それが機能することに少し驚いています。async_wrapperが戻るのを待つ必要がありますが、まさにその関数内で待機しています。論理的には、デッドロックになるはずですが、そうではありません。

また、 async_wrapperの最後に行を追加して、将来のオブジェクトを手動で空にしようとしました。

our_future = std::future<void>();

これもブロックしません。

于 2016-09-18T22:08:04.267 に答える