在没有活动异常的情况下调用C++终止

111*_*111 70 c++ multithreading deadlock c++11

我通过线程获得C++错误:

terminate called without an active exception
Aborted
Run Code Online (Sandbox Code Playgroud)

这是代码:

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template<typename TYPE>
class blocking_stream
{
public:
    blocking_stream(size_t max_buffer_size_)
        :   max_buffer_size(max_buffer_size_)   
    {
    }

    //PUSH data into the buffer
    blocking_stream &operator<<(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx); 
        while(buffer.size()>=max_buffer_size)
            stop_if_full.wait(mtx_lock);

        buffer.push(std::move(other));

        mtx_lock.unlock();
        stop_if_empty.notify_one();
        return *this;
    }
    //POP data out of the buffer 
    blocking_stream &operator>>(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx);
        while(buffer.empty())
            stop_if_empty.wait(mtx_lock);

        other.swap(buffer.front()); 
        buffer.pop();

        mtx_lock.unlock();
        stop_if_full.notify_one();
        return *this;
    }

private:
    size_t max_buffer_size;
    std::queue<TYPE> buffer;
    std::mutex mtx;
    std::condition_variable stop_if_empty,
                            stop_if_full;
    bool eof;   
};
Run Code Online (Sandbox Code Playgroud)

我在这个例子中模拟了我的代码:http: //www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

我做错了什么,如何修复错误?

Bar*_*ski 98

当线程对象超出范围并且处于可连接状态时,程序将终止.标准委员会对可连接线程的析构函数有两个其他选项.它可以安静地加入 - 但是如果线程被卡住,加入可能永远不会返回.或者它可以分离线程(分离的线程不可连接).但是,分离的线程非常棘手,因为它们可能会持续到程序结束并且会释放资源.因此,如果您不想终止您的程序,请确保您加入(或分离)每个线程.

  • @mangledorf:请注意,他们正在谈论aobut boost :: thread,而我正在谈论std :: thread.这两者具有不同的破坏行为.这是委员会有意识的决定. (4认同)
  • “当线程对象超出范围并且处于可连接状态时,程序将终止”您能否提供一个非常简单、可重现的示例?OP中的例子有点复杂。 (3认同)
  • 只是在 C++20 中进行了更新,“std::jthread”将在析构函数中调用“.join()”(因为它超出了范围)。我个人更喜欢它,因为它更好地遵循 RAII。 (2认同)
  • 每次我遇到这个问题时,错误消息都是完全难以理解的,直到我谷歌并偶然发现这个答案。 (2认同)

Eri*_*ski 40

如何重现该错误:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译并运行:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
terminate called without an active exception
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

您收到该错误是因为您没有加入或分离您的主题.

修复它的一种方法是,加入这样的线程:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  t1.join();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后编译并运行:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello
Run Code Online (Sandbox Code Playgroud)

修复它的另一种方法是将它分开:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() 
{ 
     {

        std::thread t1(task1, "hello"); 
        t1.detach();

     } //thread handle is destroyed here, as goes out of scope!

     usleep(1000000); //wait so that hello can be printed.
}
Run Code Online (Sandbox Code Playgroud)

编译并运行:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello
Run Code Online (Sandbox Code Playgroud)

阅读有关分离C++线程和加入C++线程的信息.


har*_*nan 17

Eric Leschinski和Bartosz Milewski已经给出了答案.在这里,我将尝试以更加初学者友好的方式呈现它.

一旦在一个作用域(它本身在一个线程上运行)中启动了一个线程,就必须在线程超出作用域之前明确地确保发生以下一种情况:

  • 只有在该线程完成执行后,运行时才会退出作用域.这是通过加入该线程来实现的.注意语言,它是与该线程连接的外部作用域.
  • 运行时使线程自行运行.因此,无论此线程是否完成执行,程序都将退出范围.该线程自行执行和退出.这是通过分离线程来实现的.例如,如果线程引用该外部作用域中的变量,则可能会导致问题.

注意,在线程连接或分离时,它可能已经完成执行.仍然必须明确地执行这两个操作中的任何一个.