3

スレッドプールで多くのジョブを実行する必要がある C++ プロジェクトに取り組んでいます。ジョブは失敗しやすいため、各ジョブが完了後にどのように終了したかを知る必要があります。ほとんどの部分で Java プログラマーである私は、Java の util.concurrent パッケージのさまざまなクラスに似た、「フューチャー」または同様のパラダイムを使用するという考えが好きです。

2 つの質問があります。1 つ目は、C++ 用にこのようなものが既に存在しますか (Boost には何も見つかりませんでしたが、十分に調べていない可能性があります)。第二に、これは C++ の正気な考えですか?

ここで達成しようとしていることの簡単な例を見つけました:

http://www.boostcookbook.com/Recipe:/1234841

このアプローチは理にかなっていますか?

4

3 に答える 3

5

Boostには、先物やその他のスレッドツールが実装されています。

get()メソッドを呼び出すと、boost::unique_future非同期実行中にメソッド内に格納された可能性のある例外が再スローされることに注意してください。

私はあなたが次のようなことをすることを提案します:

#pragma once

#include <tbb/concurrent_queue.h>

#include <boost/thread.hpp>
#include <boost/noncopyable.hpp>

#include <functional>

namespace internal
{
    template<typename T>
    struct move_on_copy
    {
        move_on_copy(const move_on_copy<T>& other) : value(std::move(other.value)){}
        move_on_copy(T&& value) : value(std::move(value)){}
        mutable T value;
    };

    template<typename T>
    move_on_copy<T> make_move_on_copy(T&& value)
    {
        return move_on_copy<T>(std::move(value));
    }
}

class executor : boost::noncopyable
{
    boost::thread thread_;

    tbb::concurrent_bounded_queue<std::function<void()>> execution_queue_;

    template<typename Func>
    auto create_task(Func&& func) -> boost::packaged_task<decltype(func())> // noexcept
    {   
        typedef boost::packaged_task<decltype(func())> task_type;

        auto task = task_type(std::forward<Func>(func));            

        task.set_wait_callback(std::function<void(task_type&)>([=](task_type& my_task) // The std::function wrapper is required in order to add ::result_type to functor class.
        {
            try
            {
                if(boost::this_thread::get_id() == thread_.get_id())  // Avoids potential deadlock.
                    my_task();
            }
            catch(boost::task_already_started&){}
        }));

        return std::move(task);
    }

public:

    explicit executor() // noexcept
    {
        thread_ = boost::thread([this]{run();});
    }

    ~executor() // noexcept
    {   
        execution_queue_.push(nullptr); // Wake the execution thread.
        thread_.join();
    }

    template<typename Func>
    auto begin_invoke(Func&& func) -> boost::unique_future<decltype(func())> // noexcept
    {   
        // Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics.
        auto task_adaptor = internal::make_move_on_copy(create_task(func));

        auto future = task_adaptor.value.get_future();

        execution_queue_.push([=]
        {
            try{task_adaptor.value();}
            catch(boost::task_already_started&){}
        });

        return std::move(future);       
    }

    template<typename Func>
    auto invoke(Func&& func) -> decltype(func()) // noexcept
    {
        if(boost::this_thread::get_id() == thread_.get_id())  // Avoids potential deadlock.
            return func();

        return begin_invoke(std::forward<Func>(func), prioriy).get();
    }

private:

    void run() // noexcept
    {
        while(true)
        {
            std::function<void()> func;
            execution_queue_.pop(func); 
                    if(!func)
                       break;
            func();
        }
    }   
};
于 2011-06-03T18:16:21.453 に答える
5

Futures は、今後の標準 (C++0x) と内部ブーストの両方に存在します。futureメイン名は同じですが、ドキュメントを読んで他のタイプを見つけ、セマンティクスを理解する必要があることに注意してください。私は Java の先物を知らないので、違いがあるとしても、どこが違うのかはわかりません。

boost のライブラリは、Anthony Williamsによって作成されました。これは、標準のその部分の定義にも関与していると思います。また、 C++ Concurrency in Actionも執筆しており、Future、タスク、Promise、および関連オブジェクトの適切な説明が含まれています。彼の会社は、C++0x スレッド ライブラリの完全な実装も販売しています (興味がある場合)。

于 2011-06-03T18:41:15.963 に答える
-1

C++ テンプレートは Java Generics よりも制限が少ないため、Future はそれらとスレッド同期プリミティブを使用して容易に移植できます。そのようなメカニズムをサポートする既存のライブラリについては、他の誰かが知っていることを願っています。

于 2011-06-03T18:15:43.403 に答える