【问题标题】:How to pass a list to a thread without copying it, while destroying the original如何在不复制列表的情况下将列表传递给线程,同时破坏原始列表
【发布时间】:2019-09-20 05:17:29
【问题描述】:

此代码创建并执行一个线程,该线程需要获取std::list<int> data 的内容,而不会复制此列表的内容并将其地址更改为内存。指向列表的指针必须对其他代码保持有效。

线程创建后,原来的列表data在主线程中被销毁,所以在这种情况下我不能使用它的地址。

我怎样才能做到这一点?我尝试过使用右值引用,但我担心如果我以这种方式尝试它可能会有一个悬空指针。这是我所拥有的:

void func(std::list<int> && data){  // <-- what should go here as an argument?
   std::sort(data.begin(), data.end());
   // do stuff with data
}

int main(){
    {
        std::list<int> data;
        data.push_back(1);
        std::thread(func, std::move(data)).detach();
    } 
    // data destroyed
}

【问题讨论】:

  • 如果这会导致内存损坏,我会感到非常惊讶。不过,您为什么要通过引用接受?除了让人们(包括你自己)感到困惑之外,没有其他理由。如果您使用 std::reference_wrapper 将列表从 main() 传递给线程,那只会是内存损坏
  • @arne - 我将列表的内容保持在同一地址(其他代码保持指向它们的指针必须保持有效),所以我必须避免复制。我希望通过右值传递显式避免复制,而通过值传递允许复制。
  • 抱歉,我不确定你的意思。这里永远不会复制向量的内容,只是交换来自​​ std::list 的原始指针。然而 main() 中的原始列表现在是空的,那么为什么要保留对它的引用呢?在上面的示例中,func() 传递了来自 std::thread 内容的引用,而不是 main() 内部变量的引用。正如我所说,您需要 std::reference_wrapper 将真正的引用传递给线程。
  • @ArneJ - 很抱歉造成混乱,我已经重写了问题以扩大并希望澄清问题
  • 不会有悬空引用,数据本身也不会移动(参见 std::list 的引用)

标签: c++ multithreading rvalue


【解决方案1】:

thread 的构造函数调用

std::invoke(decay_copy(std::forward<Function>(f)), 
            decay_copy(std::forward<Args>(args))...);

其中decay_copy定义如下:

template <class T>
std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }

您正在传递move(data)。因为decay_copy使用引用转发,所以它返回T&amp;&amp;,因为decay_t丢弃了constness和referenceness,新的list对象是使用move构造函数创建的。所以main 中的data 列表被移动到线程构造函数中(thread 将其参数存储在元组中 - 你不需要关心移动数据列表对象的生命周期。现在,问题是你想如何传递/access 已将data 列表移至func。通过复制/移动或引用,详情如下)。

现在invoke 被调用:

invoke (func, temporary list object returned by decay_copy)

这里有两种情况需要考虑:

[1] func 具有签名func(list&lt;int&gt;&amp;&amp;),在这种情况下,您只是通过引用访问移动的列表对象 - 没有复制,也没有调用移动操作。

[2] func 具有签名func(list&lt;int&gt;),在这种情况下,将在列表上调用移动构造函数。如果列表没有移动支持,这里会调用复制操作。

所以使用list&lt;int&gt;&amp;&amp;,你会保存一个移动操作。

【讨论】:

    猜你喜欢
    • 2018-05-24
    • 2010-09-18
    • 2020-09-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    • 2019-03-28
    • 1970-01-01
    • 2018-03-08
    相关资源
    最近更新 更多