【问题标题】:detached thread crashing on exiting分离的线程在退出时崩溃
【发布时间】:2016-10-26 15:40:05
【问题描述】:

我正在使用一个简单的线程池,如下所示-

template<typename T>
class thread_safe_queue // thread safe worker queue.
{
private:
    std::atomic<bool> finish;
    mutable std::mutex mut;
    std::queue<T> data_queue;
    std::condition_variable data_cond;
public:
    thread_safe_queue() : finish{ false }
    {}

    ~thread_safe_queue()
    {}

    void setDone()
    {
        finish.store(true);
        data_cond.notify_one();
    }
    void push(T new_value)
    {
        std::lock_guard<std::mutex> lk(mut);
        data_queue.push(std::move(new_value));
        data_cond.notify_one();
    }

    void wait_and_pop(T& value)
    {
        std::unique_lock<std::mutex> lk(mut);
        data_cond.wait(lk, [this]
        {
            return false == data_queue.empty();
        });
        if (finish.load() == true)
            return;
        value = std::move(data_queue.front());
        data_queue.pop();
    }
    bool empty() const
    {
        std::lock_guard<std::mutex> lk(mut);
        return data_queue.empty();
    }
};

//Thread Pool
class ThreadPool
{
private:
    std::atomic<bool> done;
    unsigned thread_count;
    std::vector<std::thread> threads;

public:
    explicit ThreadPool(unsigned count = 1);

    ThreadPool(const ThreadPool & other) = delete;
    ThreadPool& operator = (const ThreadPool & other) = delete;

    ~ThreadPool()
    {
        done.store(true);
        work_queue.setDone();
        // IF thread is NOT marked detached and this is uncommented the worker threads waits infinitely.
        //for (auto &th : threads)
        //{
         //     if (th.joinable())
         //     th.join();
        // }
    }

    void init()
    {
        try
        {
            thread_count = std::min(thread_count, std::thread::hardware_concurrency());
            for (unsigned i = 0; i < thread_count; ++i)
            {
                threads.emplace_back(std::move(std::thread(&ThreadPool::workerThread, this)));
                threads.back().detach();
              // here the problem is if i dont mark it detatched thread infinitely waits for condition.
             // if i comment out the detach line and uncomment out comment lines in ~ThreadPool main threads waits infinitely.
            }
        }
        catch (...)
        {
            done.store(true);
            throw;
        }
    }

    void workerThread()
    {
        while (true)
        {
            std::function<void()> task;
            work_queue.wait_and_pop(task);
            if (done == true)
                break;
            task();
        }
    }
    void submit(std::function<void(void)> fn)
    {
        work_queue.push(fn);
    }
};

用法如下:

struct start
{
public:
    ThreadPool::ThreadPool m_NotifPool;
    ThreadPool::ThreadPool m_SnapPool;
    start()
    {
        m_NotifPool.init();
        m_SnapPool.init();
    }
};    
int main()
{
    start s;
    return 0;
}    

我在 Visual Studio 2013 上运行此代码。问题在于主线程何时退出。程序崩溃。它抛出异常。 请帮我解决我做错了什么?如何正确停止工作线程?我花了相当长的时间,但仍然找出问题所在。

提前感谢您的帮助。

【问题讨论】:

  • 我不确定,但似乎队列会被锁定(第一个 wait_and_pop 在等待队列为空时持有互斥锁,下一个 workerThread 永远不会获得互斥锁)。如果是这种情况,线程将永远不会优雅地退出。
  • 尝试用return !data_queue.empty() || finish;替换return false == data_queue.empty();

标签: c++ multithreading c++11 visual-c++


【解决方案1】:

我不熟悉 C++ 中的线程,但使用过 C 中的线程。在 C 中,实际发生的情况是,当您从主线程创建子线程时,您必须停止主线程,直到子线程完成。如果 main 退出,线程就会变成僵尸。我认为 C 在僵尸的情况下不会抛出异常。并且可能只是因为这些僵尸而让您例外。尝试停止 main 直到孩子完成,看看它是否有效。

【讨论】:

  • 但在 C 中,您也可以将线程标记为已分离,一旦主线程完成,它就会退出,而 main 不需要等待子线程完成。我认为这就是分离线程的含义。
【解决方案2】:

main 退出时,允许分离的线程继续运行,但是对象s 被销毁。因此,当您的线程尝试访问对象 s 的成员时,您将遇到 UB。

有关您的问题的更多详细信息,请参阅此问题的已接受答案:What happens to a detached thread when main() exits?

【讨论】:

    【解决方案3】:

    经验法则是不要从主线程中分离线程,而是通知线程池应用程序正在结束并加入所有线程。或者按照What happens to a detached thread when main() exits?中的回答进行操作

    【讨论】:

      猜你喜欢
      • 2011-05-17
      • 1970-01-01
      • 2011-09-28
      • 2017-06-29
      • 2018-08-12
      • 2011-11-12
      • 2010-12-15
      • 1970-01-01
      • 2011-09-03
      相关资源
      最近更新 更多