在 C++ 中创建 std 线程会使程序崩溃

Posted

技术标签:

【中文标题】在 C++ 中创建 std 线程会使程序崩溃【英文标题】:Creating std threads in C++ crashes the program 【发布时间】:2015-11-25 05:22:26 【问题描述】:

每当我使用线程执行以下代码时,程序都会出现此错误:

调试错误! 程序:... /path/to/.exe

abort() 已被调用

我想创建一个调用成员函数的线程。这是我正在使用的功能:

void ServerVote::createConnexionThreads()

    for (int i = 0; i <= 50; ++i)
    
        m_connexionThreads.push_back(&(std::thread(&ServerVote::acceptConnection,*this, i)));
    
    for (int i = 0; i <= 50; ++i)
    
        m_connexionThreads[i]->join();
    

如果需要,我可以提供额外的代码。使用调试器时,我发现程序在创建第一个线程后立即崩溃,在线程被 push_back 之后。然后调用 ~thread() 并在此函数内崩溃。这是向量声明:

std::vector<std::thread*> m_connexionThreads;

我使用的是 Visual Studio 2015。acceptConnection 函数内部有一个 while(true),计划稍后终止。

编辑:

感谢您的回答,但是当使用线程对象而不是指针时我无法编译。所以当我尝试推入这个向量时:

std::vector<std::thread> m_connexionThreads;

for (int i = 0; i <= 50; ++i)

        m_connexionThreads.push_back((std::thread(&ServerVote::acceptConnection,*this, i)));

编译时出现此错误:

error C2280: 'std::thread::thread(const std::thread &)': attempting to reference a deleted function

【问题讨论】:

您正在尝试使用指向您在循环中创建的临时对象的指针填充容器。不太可能奏效。 【参考方案1】:

您不应尝试在任何情况下使用临时地址。事实上,这是 MSVC 中允许此代码的错误。任何符合标准的编译器都会在此处产生错误。

相反,您应该像这样使用线程对象(请参阅我在代码下方的编辑,了解为什么这是首选):

#include <thread>
#include <vector>

void acceptConnection(int);

void foo() 
  std::vector<std::thread> vec;
  for (int i = 0; i <= 50; ++i)
        vec.push_back(std::thread(acceptConnection, i));

为什么这种方法优于使用分配的指向线程对象的指针?有多种好处:

    打字少了——即使没有别的,一切都是平等的(尽管它们不是!)少打字胜过多打字。 使用指针需要谨慎。例如,你不应该使用原始指针作为向量数据类型,你应该使用unique_ptr 来确保自动内存清理——这使得语法更加丑陋! 使用动态分配的内存会拖累性能。你被击中了两次——第一次是分配内存,第二次是释放它。为什么要遭受这种惩罚?

【讨论】:

谢谢,但是我尝试使用指向线程的指针而不是线程对象的原因是因为当我使用线程对象时我的代码无法编译。它说我正在尝试引用 std::thread 的复制构造函数(已删除)。【参考方案2】:

您正在堆栈中创建线程的本地实例,获取其地址并将其推送到向量。线程对象将在方法退出时被删除,因此您将留下一个指向已删除对象的指针。

您应该使用new 在堆中创建线程对象,这样它就不会在方法退出时被删除,或者不使用指向线程对象的指针。

【讨论】:

认真的吗?新的?糟糕的建议。 您需要解释吗?请继续关注我的答案。 @SergeyA 是的,如果他想存储指针,需要解释为什么不这样做。 显然,他不需要存储指针。最有可能的是,OP 根本不知道在这里做什么。没有任何情况需要存储动态分配的指向 std::thread 的指针。 @SergeyA 这就是为什么我使用了想要这个词而不是需要

以上是关于在 C++ 中创建 std 线程会使程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

发现为啥在我的 C++ 应用程序中创建线程及其作用的最佳方法是啥?

C++ 在 Windows API 中创建一个单独的线程,程序终止?

如果文件描述符关闭,Linux write() 会使应用程序崩溃

如何检查是不是在 Visual C++ 应用程序中的第三方 DLL 中创建了新线程

从完成处理程序/块中引发自定义异常会使目标 c 中的应用程序崩溃

C++ 全系统崩溃,仅发布模式