【问题标题】:Create shared packaged_task that accepts a parameter with forwarding创建接受带有转发参数的共享 packaged_task
【发布时间】:2015-09-15 16:42:50
【问题描述】:

您好,我不知道如何编写正确的队列绑定并执行传递给 OCRQueue::enqueue() 方法的 lambda 表达式

// the task queue
std::queue< std::function<void(OCRK*)> > tasks;

// add new work item to the pool
template<class F>
auto OCRQueue::enqueue(F&& f)
-> std::future<typename std::result_of<F(OCRK*)>::type>
{
    using return_type = typename std::result_of<F(OCRK*)>::type;

    auto task = std::make_shared< std::packaged_task<return_type()> >
    (
        // how to initialize this task so that it can be called 
        // task(OCRK*) passing the parameter to f(OCRK*)
        std::bind
        (
            std::forward<F>(f)
        )
    );

    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);

        // don't allow enqueueing after stopping the pool
        if (stop)
            throw std::runtime_error("enqueue on stopped thread_pool");

        // this fails because task does not accept parameters
        tasks.emplace([task](OCRK* ocr){ task(ocr); });
    }
    condition.notify_one();
    return res;
}

目前这无法在“auto task =”上编译,因为 f 需要一个 OCRK* 类型的参数:

错误 6 错误 C2064:术语不计算为采用 0 个参数的函数 C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xrefwrap 58 1 Skilja.PR.API

On: 1> d:\sourcecode\skilja\alpr\alpr\skilja.pr.api.native\OCRQueue.h(51) : 参见函数模板实例化 'std::shared_ptr> std::make_shared, std::_Bind &,>>(std::_Bind &,> &&)' 正在编译

预期的用法是这样的:

OCRQueue ocrPool(std::thread::hardware_concurrency());
auto work = [](OCRK* ocr)
{
    return ocr->DoSomething();
};
future<DoSomethingResult> result = ocrPool.enqueue(work);

OCRK* 将在出队并在另一个线程中执行时传递给入队函数。

【问题讨论】:

    标签: c++ multithreading c++11 lambda std


    【解决方案1】:

    要创建一个接受单个参数的可调用对象,您需要告诉bind 为参数使用占位符:

    std::bind( std::forward<F>(f), std::placeholders::_1 )
    

    这告诉bind 留下一个未绑定的参数,当您调用函数对象时必须提供该参数。

    但我完全不明白你为什么使用bind,你没有绑定任何东西,f 已经是一个接受单个参数的可调用对象,你为什么不把它传递给packaged_task构造函数?

    还有一个问题,就是你说你想要一个接受单个参数的任务,但是你声明了packaged_task&lt;return_type()&gt;,这是一个不带参数的任务。我想你想要:

    auto task = std::make_shared< std::packaged_task<return_type(OCRK*)> >(std::forward<F>(f));
    

    还有:

        tasks.emplace([task](OCRK* ocr){ task(ocr); });
    

    这仍然会失败,因为taskshared_ptr,所以它是不可调用的。应该是:

        tasks.emplace([task](OCRK* ocr){ (*task)(ocr); });
    

    【讨论】:

    • 因为在入队时我没有 OCRK* 来调用它。这将在另一个拥有 OCRK* 的工作线程的线程中执行。
    • 是的,这正是您在调用bind 时使用占位符的原因,表示“我现在没有这个参数,但稍后会提供”。但这不是必需的。 f 已经是一个带有一个参数的函数对象,你必须在调用它时提供它。
    • 我需要创造一个未来才能回归。有没有办法在没有 std::packaged_task 的情况下创建它?
    • 是的,您可以使用 promise 和 lambda 手动完成,但 packaged_task 更简单。另外,请阅读我的答案的最新版本。 packaged_task&lt;result_type()&gt; 是错误的,是您的问题之一。
    • 感谢您的帮助,它可以编译并且似乎可以正常工作。我会接受答案。您对共享 ptr 的看法也是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多