多线程-为啥在引用上工作不会改变它,而在指针上工作正常[重复]

Posted

技术标签:

【中文标题】多线程-为啥在引用上工作不会改变它,而在指针上工作正常[重复]【英文标题】:Multithreading - why working on a reference doesn't change it, while on a pointer works properly [duplicate]多线程-为什么在引用上工作不会改变它,而在指针上工作正常[重复] 【发布时间】:2014-07-24 23:22:04 【问题描述】:

谁能解释一下原因

void doSomething(vector<int>& vec) 
    for (int i = 0; i < 100; ++i)
        vec.push_back(i);


int main(int argc, char** argv) 
    vector<int> v;
    thread t1(doSomething, v);
    thread t2(doSomething, v);
    t2.join();
    t1.join();
    cout << v.size() << endl;
    return 0;

打印 0,而带有指针的相同内容打印 200

void doSomething(vector<int>* vec) 
    for (int i = 0; i < 100; ++i)
        vec->push_back(i);


int main(int argc, char** argv) 
    vector<int>* v = new vector<int>();
    thread t1(doSomething, v);
    thread t2(doSomething, v);
    t2.join();
    t1.join();
    cout << v->size() << endl;
    return 0;

在这里处理引用不应该等于(处理指针)吗?

编辑:故意不是线程安全的

您能否提供我为什么需要使用 std::ref 的参考?

【问题讨论】:

你很幸运能得到任何东西。您有两个线程,一个向量并且没有锁定。任何事情都有可能发生。 @ZanLynx 绝对是指针版本。使用参考版本,它实际上是相当安全的,如果不是 OP 所期望的,如链接副本中所述。 @aruisdante:是的。如果它像 mewa 预期的那样工作,它也会有同样的问题。 @ZanLynx 我是故意这样做的,我想看看并发修改发生时会发生什么 【参考方案1】:

1)您的代码不是线程安全的(在向量上并发push_back

2) 参数默认按值传递给std::thread。这种复制参数的语义对于线程来说是很自然的:任何参数都将被复制/移动到线程可访问的存储中。这样做,std:::thread 会尽力避免对共享对象的并发访问。

使用std::ref 通过引用您的线程可调用来传递参数:

thread t1(doSomething, std::ref(v));
thread t2(doSomething, std::ref(v));
                        ^^^^^^^^

没有std::ref,gcc 和clang 都不会编译这段代码。


为了将来参考,std::thread 构造函数在 C++ 标准的第 30.3.1.2 节中进行了描述。

【讨论】:

您能否发布参考并解释原因?另外,它是用 msvc 实现的 @mewa 在这个答案的链接中有解释。主狙击手之前的code highlighs 都是指向各自模板的链接。检查std::thread的构造函数以供参考 是的。我还进行了编辑以解释更多。基本上,std::thread 在参数上使用复制语义以避免(默认情况下)处理共享对象。【参考方案2】:

std::thread 不幸的是按值获取参数。即使您将其设置为通过引用获取,它最终仍会复制它。您可以使用 std::ref 通过引用传递。

【讨论】:

以上是关于多线程-为啥在引用上工作不会改变它,而在指针上工作正常[重复]的主要内容,如果未能解决你的问题,请参考以下文章

结构中的指针分配不工作,为啥值没有改变?

为啥 href 在 iOS 上不起作用,而在包括 Mac 在内的任何其他设备上都可以正常工作?

为啥线程在单核 CPU 上工作?

指针和引用的区别

对 NULL 指针连续 free多次会出错吗?为啥?

从一个简单例子来理解js引用类型指针的工作方式