【问题标题】:Howto return a future when pushing to a thread pool推送到线程池时如何返回未来
【发布时间】:2020-08-15 07:46:12
【问题描述】:

我尝试将具有返回值的任务推送到线程池:

template<class Function>
auto enqueue(Function&& f)
{
    using ReturnType = std::result_of_t<std::decay_t<Function>()>;
    std::promise<ReturnType> ret_promise;
    auto fut = ret_promise.get_future();
    auto task = UniqueFunction<void()>(
       [do_it = std::move(f), ret = std::move(ret_promise)]() mutable {
           ret.set_value(do_it());
       });
    {
        std::lock_guard lock{m_mtx};
        m_tasks.push(std::move(task));
        m_cv.notify_one();
    }
return fut;
}

循环看起来像这样:

void performTasks()
{
    while(true)
    {
        std::unique_lock<std::mutex> lock{m_mtx};
        m_cv.wait(lock, [this]() { return !m_tasks.empty() || m_terminate; });
        if(!m_tasks.empty())
        {
            auto task = std::move(m_tasks.front());
            m_tasks.pop();
            lock.unlock();
            task();
        }
        else
        {
            return;
        }
    }
}

Helgrind 在尝试等待结果时抱怨数据竞争:

线程 #1 在 0x5DFB618 读取大小为 8 时可能出现数据争用

这与线程 #2 先前写入的大小为 8 的冲突

这是误报还是上面的实现有问题?

【问题讨论】:

  • 请发布一个完整的工作示例。

标签: c++ multithreading promise future


【解决方案1】:

我在您的代码中看不到数据竞争。问题可能出在其他地方。就像在没有适当同步的情况下修改m_terminate

也可能是误报。根据documentation,Helgrind 在使用 POSIX pthreads 线程原语的程序中检测同步错误。因此,如果 Helgrind 不使用 pthread 原语,则可能无法识别特定代码段是否正确同步。

std::mutexstd::condition_variablestd::atomic 等同步机制可能会或可能不会在其实现中使用 pthread 原语。特别是,std::atomics 很可能不会。

我建议您使用 ThreadSanitizer 而不是 Helgrind 来检测线程错误。

【讨论】:

  • 使用ThreadSanitizer运行代码时,没有问题。所以是的,它是 std::atomic。 std::mutex 和 std::condition_variable 在后台使用 pthread。
  • m_terminate 是一个原子布尔值吗?
  • 否,但由同一个互斥锁保护。但是期货在获取数据时使用原子操作。因此,它将在 helmgrind 中失败。
猜你喜欢
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多