【问题标题】:Vector of thread pointers, push_back causes crash线程指针向量,push_back 导致崩溃
【发布时间】:2019-09-16 05:36:43
【问题描述】:

我是 C++ 新手,最近在研究并发性。 我尝试运行这个简单的程序来演示线程:

#include <vector>
#include <thread>
#include <stdio.h>

void threadWork()
{
    printf("WORKER THREAD EXECUTING");
}

int main()
{
    printf("INSTANTIATE THREAD\n");
    std::vector<std::thread *> threadList;
    threadList.push_back(&std::thread(&threadWork));
    printf("THREAD INSTANTIATED JOINING...\n");
    for (std::thread* t : threadList)
    {
        t->join();
    }
    printf("THREADS JOINED\n");
    return 0;
}

在调用 push_back() 后,程序因调用 abort() 而崩溃(我在 Windows 上运行)
为什么这段代码在运行时会崩溃?

【问题讨论】:

  • 为什么要保留一个指针的向量?你的指针指向什么?你懂指针吗?
  • 不能取临时地址。
  • 注:这甚至不会在 VS 之外编译
  • 据我了解,添加到向量的指针指向实例化线程对象的地址(&std::thread(&threadWork))。我正在使用指针,因为我正在练习并且据我所知指针更灵活。
  • 据我了解,指针更灵活 -- 不,这不是使用指针的理由。当你需要使用指针时,你就使用指针。

标签: c++ multithreading


【解决方案1】:
std::vector<std::thread *> threadList;
threadList.push_back(&std::thread(&threadWork));

这里取一个临时地址。

这在 C++ 中是不允许的,但 Visual Studio 允许您这样做。

很遗憾,因为临时对象在调用结束时被销毁,所以你的向量只包含一个悬空指针。

此外,由于您不是join()ing 或detach()ing 线程,因此销毁其std::thread(当它超出范围时发生)会导致您的程序std::terminate()(通常被认为是崩溃)。

我建议重新阅读您的 C++ 书中有关线程管理的章节,这样您就可以确保以安全的方式进行操作。


忘记这里的指针;你不需要它们。相反,只需要一个简单的线程向量,然后使用emplace_back 直接构造您的元素,如下所示:

std::vector<std::thread> threadList;
threadList.emplace_back(&threadWork);

然后在程序完成之前确保你join()你的线程。

【讨论】:

  • 我认为他的根本问题是他不太熟悉 C++ 中不同类型的内存(堆、堆栈、静态、线程本地......)。如果他是,他甚至不会尝试他尝试过的东西。
  • @BitTickler 具有讽刺意味的是,C++ 对“堆”或“堆栈”一无所知。您指的是存储持续时间。是时候复习了;)
【解决方案2】:

程序中止,因为如果您在 std 线程运行或完成时销毁它,它就会中止。

发生这种情况是因为您正在存储一个指针向量并获取临时对象的地址。第一个是个坏主意,第二个在 C++ 中是非法的,但 MSVC 默认允许这样做。

在 C++ 中,您应该默认使用值,尤其是标准库类型。当你不使用值时,使用智能指针。使用原始指针通常应该仅用于某些函数参数,有时在具有引用语义的结构/类中,或者在进行 C 互操作时。

所以这里,

std::vector<std::thread> threadList;

是一个线程向量。没有无意义的指针。

threadList.emplace_back(&threadWork);

创建一个运行线程工作的新线程/

for(auto& thread:threadList){
   thread.join();
}

加入线程;这将等到线程完成。不做这样的事情会让你的程序中止。

大家一起:

printf("INSTANTIATE THREAD\n");
std::vector<std::thread> threadList;
threadList.emplace_back(&threadWork);
printf("THREAD INSTANTIATED\n");
for(auto& thread:threadList){
   thread.join();
}

【讨论】:

  • 哈,直到~thread() 没有detach()。认为确实如此,因为 Boost 已经习惯了,但是自从我上次费心研究它以来,即使是那个 impl 也已经继续前进了。显示了即使是我认为的最基本的功能也保持最新是多么重要......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
相关资源
最近更新 更多