【问题标题】:Unexpected behavior using std::map with std::thread使用带有 std::thread 的 std::map 的意外行为
【发布时间】:2017-09-07 09:43:22
【问题描述】:

所以我的应用程序需要一个线程池,这导致我创建了一个std::map<int, std::thread> 对象。 我遇到了一些非常意外的行为,可以简化为:

std::map<int, std::thread> threads;

threads.insert(std::pair<int, std::thread>(1, std::thread([]() {
        std::cout << "I'm the first thread and I'm gonna work\n";
    })));
threads[1].join();

std::cout << "Thread 1 joinable? " << threads[1].joinable() << "\n";

threads.insert(std::pair<int, std::thread>(1, std::thread([]() {
        std::cout << "I'm not gonna work at all\n";
    })));
threads[1].join();

输出是

I'm the first thread and I'm gonna work
Thread 1 joinable? 0

紧接着,std::terminate() 被调用并且程序接收到 SIGABRT 信号。

实时调试提示 terminate 被调用,因为 joinable() 是真的,但我刚刚检查并发现它不是!

此外,克服它的方法只是在join()ing 之后添加以下行:

threads.erase(1);

这让我有点困惑,因为看起来std::thread 的新实例是在我调用insert 之前创建的...有人可以提示我这种意外行为吗?

【问题讨论】:

  • 在 stdout 上跟踪时,不要忘记刷新。
  • @molbdnilo - 换行应该这样做。
  • @OliverCharlesworth '\n' 不会刷新 std::cout
  • @FrançoisAndrieux - 这对我来说是个新闻:/(至少在 cout 在典型环境中包装标准输出的世界中。)你能澄清一下吗?
  • @OliverCharlesworth: \n 如果直接连接到终端,std::cout 会刷新,否则不会。 stackoverflow.com/q/796865/845092

标签: c++ multithreading c++11 stl


【解决方案1】:

来自http://en.cppreference.com/w/cpp/container/map/insert

如果容器尚未包含具有等效键的元素,则将元素插入容器中。

您的地图已经在键 1 处包含一个元素,因此第二个 threads.insert 不会做任何事情。您只是想在同一个std::thread 上加入两次。这就是 threads.erase(1); 解决问题的原因,您的地图不再包含键 1 处的线程。

【讨论】:

  • 太好了,谢谢。所以没有直接的 API 可以覆盖现有密钥,对吗?
  • @OmerPerry treads[1] = std::thread( [](){ /* do work*/ } ); 将用一个新线程“覆盖”键 1 处的线程。没有在单个调用中删除然后替换元素的方法,但是移动分配应该对任何可移动类型执行相同的操作。
猜你喜欢
  • 1970-01-01
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 2020-10-04
  • 2023-04-07
  • 2012-12-19
  • 2016-10-20
  • 1970-01-01
相关资源
最近更新 更多