我在线程方面遇到 C++ 错误:
terminate called without an active exception
Aborted
这是代码:
#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;
};
我围绕这个示例对我的代码进行了建模: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
我做错了什么以及如何修复错误?
当线程对象超出范围并且处于可连接状态时(即 - 假设线程对象名为
t
那么 t.joinable()
返回 true),程序将终止。标准委员会对于可连接线程的析构函数还有另外两个选择。它可以悄悄地加入——但如果线程被卡住,加入可能永远不会返回。或者它可以分离线程(分离的线程不可连接)。然而,分离线程非常棘手,因为它们可能会一直存在到程序结束并扰乱资源的释放。因此,如果您不想终止程序,请确保加入(或分离)每个线程。
如何重现该错误:
#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;
}
编译并运行:
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)
您收到该错误是因为您没有加入或分离线程。
解决此问题的一种方法是,像这样加入线程:
#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;
}
然后编译运行:
el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello
另一种修复方法,像这样拆开:
#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.
}
编译并运行:
el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello
阅读有关分离 C++ 线程和加入 C++ 线程的内容。
Eric Leschinski 和 Bartosz Milewski 已经给出了答案。在这里,我会尝试以更适合初学者的方式来呈现。
一旦线程在某个范围内启动(其本身在线程上运行),必须显式确保在线程超出范围之前发生以下情况之一:
注意,当线程加入或分离时,它可能已经完成执行。仍然必须显式执行这两个操作中的任何一个。
首先定义一个线程。如果在调用线程析构函数之前从未调用 join() 或 detach(),程序将中止。
如下所示,调用线程析构函数而不首先调用 join (等待其完成)或 detach 可以保证立即调用 std::terminate 并结束程序。
隐式分离或加入 joinable() 线程 析构函数可能会导致难以调试正确性(对于分离) 或仅在发生异常时遇到的性能(对于连接)错误 上调。因此,程序员必须确保析构函数永远不会 当线程仍然可连接时执行。
是的,线程必须是join()。当主出口
只要你的程序死了,然后没有分离或加入线程,就会发生这个错误。在不分离和加入线程的情况下,创建线程后应该无限循环。
int main(){
std::thread t(thread,1);
while(1){}
//t.detach();
return 0;}
同样有趣的是,在睡眠或循环之后,线程可以分离或连接。另外,通过这种方式,您不会收到此错误。
下面的例子也表明,第三个线程无法在主线程死亡之前完成他的工作。但只要您在代码中的某个位置分离,这个错误也不会发生。 第三个线程休眠 8 秒,但主线程将在 5 秒后死亡。
void thread(int n) {std::this_thread::sleep_for (std::chrono::seconds(n));}
int main() {
std::cout << "Start main\n";
std::thread t(thread,1);
std::thread t2(thread,3);
std::thread t3(thread,8);
sleep(5);
t.detach();
t2.detach();
t3.detach();
return 0;}