线程没有被分离

tem*_*boy 3 c++ multithreading c++11

我正在尝试创建一个线程池.我有一个std::unordered_map将线程ID映射到std::threads(workers).线程ID是等待将任务推入线程池(waiters)的线程的ID .任务由std::stack(tasks)表示.将任务推入池后,任务将从堆栈中弹出,并成为线程函数,作为映射的"值"部分.

在析构函数中,我尝试分离仍在运行的所有线程.但我仍然得到以下异常:

terminate called without an active exception
bash: line 7: 16881 Aborted                 (core dumped) ./a.out
Run Code Online (Sandbox Code Playgroud)

这意味着线程没有分离,程序终止.但是我的析构函数会遍历元素并将它们分离(我相信).为什么会发生这种情况,我该如何解决?

#include <queue>
#include <stack>
#include <mutex>
#include <thread>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <unordered_map>
#include <condition_variable>

template <class F>
class thread_pool
{
    static_assert(std::is_function<F>::value, "F must have function type");
public:
    thread_pool();
    ~thread_pool();
    template <class Task>
    void push(Task&&);
private:
    std::unordered_map<std::thread::id, std::thread> workers;
    std::queue<std::thread> waiters;
    std::stack<std::function<F>> tasks;
    static std::size_t max;
private:
    std::condition_variable m_cond;
    std::mutex m;
private:
    void wait_for_tasks();
};

template <class F>
std::size_t thread_pool<F>::max(10);

template <class F>
thread_pool<F>::thread_pool()
{
    std::lock_guard<std::mutex> lock(m);
    for (std::size_t i = 0; i < max; ++i)
        waiters.emplace(&thread_pool<F>::wait_for_tasks, this);
}

template <class F>
void thread_pool<F>::wait_for_tasks()
{
    while (true)
    {
        std::unique_lock<std::mutex> lock(m);
        m_cond.wait(lock, [this] { return !tasks.empty(); });

        auto f = tasks.top();
        tasks.pop();
        auto& th = workers[std::this_thread::get_id()];

        if (th.get_id() == std::thread::id())
            th = std::thread(f);
    }
}

template <class F>
template <class Task>
void thread_pool<F>::push(Task&& t)
{
    {
        std::lock_guard<std::mutex> lock(m);
        tasks.emplace(std::forward<Task>(t));
    }
    m_cond.notify_all();
}

template <class F>
thread_pool<F>::~thread_pool()
{
    std::for_each(workers.begin(), workers.end(), [] (std::pair<std::thread::id const, std::thread>& p)
    {
        if (p.second.joinable())
            p.second.detach();
    });

    while (!waiters.empty())
    {
        auto& t = waiters.front();
        waiters.pop();
        if (t.joinable())
            t.detach();
    }
}

int main()
{
    thread_pool<void ()> pool;
}
Run Code Online (Sandbox Code Playgroud)

我甚至不确定这是最好的方法,这是我第一次制作它.这是一个演示.

qua*_*dev 5

在你的池析构函数中,你pop 分离线程之前调用,有效地破坏了一个可连接的线程:标准保证这将调用std::terminate

首先分离线程,然后将其弹出队列:

while (!waiters.empty())
{
    auto& t = waiters.front();

    if (t.joinable())
        t.detach();

    waiters.pop();
}
Run Code Online (Sandbox Code Playgroud)