【问题标题】:Passing 2 pointers to 2 threads but they end up sharing the same将 2 个指针传递给 2 个线程,但它们最终共享相同
【发布时间】:2013-11-29 12:55:53
【问题描述】:

我想这个问题已经出现了,它肯定显示了我在线程世界中的初学者水平,但我无法找到任何以前的问题或其他资源来解决它。我浏览了最常见的 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 的)如何工作的理解存在缺陷,如果这可以从代码中推断出来的话。

【问题讨论】:

  • 我不了解所有 C++11 的东西,但似乎您正在将 &amp;g 传递给线程,但 g 是一个在结束时被销毁的对象环形。因此未定义的行为。
  • 令人印象深刻的错误是非常基本的,但我被这个线程的新颖性所吸引,并专注于其他地方! :)
  • "...正常的风格是在创建shared_ptr的时候给一个new堆对象"

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


【解决方案1】:

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

【讨论】:

  • 你的解释很有道理。谢谢。
【解决方案2】:

您将指向g 的指针传递给每个线程。这样所有线程都接收到指向同一个变量的指针。因为您同时修改g 以使其执行,所以您会得到不确定的响应。只需将[&amp;g,&amp;mgx] 更改为[g,&amp;mtx] 即可修复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 1970-01-01
    • 1970-01-01
    • 2015-10-12
    • 1970-01-01
    • 2011-05-20
    • 2021-03-10
    相关资源
    最近更新 更多