gpt4 book ai didi

c++ - 调用 join 时如何修复 `terminate called without an active exception`

转载 作者:行者123 更新时间:2023-11-30 02:15:42 29 4
gpt4 key购买 nike

我编写了一个简单的线程池实现,但出现terminate called without an active exception 错误。我检查了线程是否可连接,然后尝试调试调用析构函数的位置,但没有成功。

workerpool.hpp

#ifndef WORKERPOOL_H
#define WORKERPOOL_H

#include <condition_variable>
#include <iostream>
#include <memory>
#include <mutex>
#include <optional>
#include <queue>
#include <thread>
#include <vector>

class task {
public:
virtual void operator()() = 0;
virtual ~task() = default;
};

class WorkerPool {
private:
class Worker {
private:
std::shared_ptr<WorkerPool> wp;
long id;

public:
Worker(std::shared_ptr<WorkerPool> _wp, long _id) : wp(_wp), id(_id) {
std::cout << "Worker " << id << " created" << std::endl;
};
~Worker() { std::cout << "Worker " << id << " destroyed" << std::endl; }

void operator()() {
while (!wp->stop) {
auto t = wp->fetch_task();
if (!t.has_value())
continue;
else
t.value()->operator()();
}
std::cout << "thread " << id << " ended" << std::endl;
};
};

std::vector<std::thread> workers;

std::queue<std::unique_ptr<task>> q;
std::condition_variable cv;
std::mutex mx;

std::optional<std::unique_ptr<task>> fetch_task() {
std::unique_lock l(mx);
cv.wait(l, [&] { return !q.empty() || stop; });
if (stop)
return {};
auto res = std::move(q.front());
q.pop();
return std::move(res);
};

public:
WorkerPool() {
std::cout << "worker pool created" << std::endl;
for (long i = 0; i < std::thread::hardware_concurrency(); i++) {
workers.push_back(
std::thread(Worker(std::shared_ptr<WorkerPool>(this), i)));
}
}

~WorkerPool() {
std::cout << "worker pool destroyed" << std::endl;
terminate();
for (size_t i = 0; i < workers.capacity(); i++) {
if (workers[i].joinable())
workers[i].join();
}
}

WorkerPool(WorkerPool const &) = delete;
WorkerPool &operator=(WorkerPool const &) = delete;
WorkerPool(WorkerPool &&) = delete;
WorkerPool &operator=(WorkerPool &&) = delete;

bool stop;

void submit(std::unique_ptr<task> t) {
std::lock_guard l(mx);
q.push(std::move(t));
cv.notify_one();
}

void terminate() {
stop = true;
cv.notify_all();
}
};

#endif // WORKERPOOL_H

main.cpp

#include <workerpool.hpp>

#include <condition_variable>
#include <iostream>
#include <mutex>

using namespace std;

class foo : public task {
public:
void operator()() override { cout << "test" << endl; }
};

int main(int argc, char *argv[]) {

WorkerPool wp;

wp.submit(make_unique<foo>());

wp.terminate();

cout << "program ended" << endl;
return 0;
}

控制台输出:

> make run
rm -f bin/*
clang++ -std=c++17 -fuse-ld=lld -pthread -Iinclude -Llib -O2 src/main.cpp -o bin/main
./bin/main
worker pool created
Worker 0 created
Worker 0 destroyed
Worker 0 destroyed
Worker 1 created
Worker 1 destroyed
Worker 1 destroyed
Worker 2 created
Worker 2 destroyed
Worker 2 destroyed
Worker 3 created
Worker 3 destroyed
Worker 3 destroyed
thread 0 ended
Worker 0 destroyed
worker pool destroyed
program endedthread 2 ended
Worker 2 destroyed
worker pool destroyed

worker pool destroyed
terminate called without an active exception
make: *** [Makefile:32: run] Aborted (core dumped)

最佳答案

std::shared_ptr<WorkerPool>(this)

你不能只是那样做。您告诉 shared_ptr 它拥有该对象,但它没有。它的生命周期已经在别处管理(在本例中,main 中的“堆栈上”)。

因此,您显然以双重删除结束(注意 2 × “worker pool destroyed”)。形式上,结果是未定义的,特别是当您为每个 工作线程创建更多不相关的 shared_ptr 时:如果程序没有崩溃,我打赌您会看到4×那条线。

有很多方法可以做到这一点,using enable_shared_from_this , 虽然that cannot work in the constructor (因为“原始”shared_ptr 还没有完成取得所有权)。

关于c++ - 调用 join 时如何修复 `terminate called without an active exception`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55850901/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com