将2个指针传递给2个线程,但它们最终共享相同的内容

时间:2013-11-29 12:55:53

标签: c++ multithreading c++11 thread-safety shared-ptr

我想这个问题已经出现了,它肯定会在线程世界中显示我的初学者级别,但我无法找到任何先前的问题或其他资源来解决它。我已经介绍了最常见的C ++ 11线程介绍(例如thisthisthis),但它没有帮助。

这是我的代码:

mutex mtx;
vector<thread> threads;

for(vcit = vc.begin(); vcit != vc.end(); ++vcit) {
    const std::shared_ptr<Graph> g = graphs.at(*vcit);

    cout << "Graph (outside thread): " << g->name << endl;
    threads.push_back(thread(
        [&g, &mtx] () {
            lock_guard<mutex> guard(mtx);
            cout << "Graph (inside thread): " << g->name << endl;
        }
    ));
}

for(thread& t : threads) {
    t.join();
} 

我希望每个线程都接收不同的指针,但是程序的输出如下(对于向量vc中的2个元素):

Graph (outside thread): ABC
Graph (outside thread): DEF
Graph (inside thread): DEF
Graph (inside thread): DEF

有时程序会“正常”并输出:

Graph (outside thread): ABC
Graph (inside thread): ABC
Graph (outside thread): DEF
Graph (inside thread): DEF

(注意现在外部和内部输出的混合顺序)。我试图从lambda转移到functor对象,但这没有任何帮助,程序表现出相同的行为。

我想知道代码的问题在哪里以及我对线程(或者shared_ptr可能)如何工作的理解是有缺陷的,如果可以从代码中推断出来的话。

2 个答案:

答案 0 :(得分:10)

lambda通过引用捕获g,实际上是存储指向仅存在于for循环内的内存的指针。虽然它没有定义行为,因为内存在堆栈上,但两个地址的概率相同。因此,有时两个线程将读取相同的值,有时它们会读取不同的值 - 有时它们甚至可以读取垃圾值。

答案 1 :(得分:3)

您正在向每个线程传递指向g的指针。这样所有线程都会收到指向同一变量的指针。因为您同时修改g执行,所以会得到非确定性响应。只需将[&g,&mgx]更改为[g,&mtx]即可解决问题。