首页 > 解决方案 > 创建新线程导致异常

问题描述

我有一个计时器,它将创建一个新线程并在调用通知函数之前等待计时器到期。它在第一次执行期间正常工作,但是当第二次启动计时器时,会抛出异常以尝试创建新线程。调试输出显示前一个线程在尝试创建新线程之前已经退出。

计时器.hpp:

 class TestTimer
{
private:
    std::atomic<bool> active;
    int timer_duration;
    std::thread thread;
    std::mutex mtx;
    std::condition_variable cv;
    void timer_func();
public:
    TestTimer() : active(false) {};
    ~TestTimer() {
        Stop();
    }
    TestTimer(const TestTimer&) = delete;               /* Remove the copy constructor */
    TestTimer(TestTimer&&) = delete;                    /* Remove the move constructor */
    TestTimer& operator=(const TestTimer&) & = delete;  /* Remove the copy assignment operator */
    TestTimer& operator=(TestTimer&&) & = delete;       /* Remove the move assignment operator */
    bool IsActive();
    void StartOnce(int TimerDurationInMS);
    void Stop();

    virtual void Notify() = 0;
};

计时器.cpp:

void TestTimer::timer_func()
{
    auto expire_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(timer_duration);
    std::unique_lock<std::mutex> lock{ mtx };
    while (active.load())
    {
        if (cv.wait_until(lock, expire_time) == std::cv_status::timeout)
        {
            lock.unlock();
            Notify();
            Stop();
            lock.lock();
        }
    }
}

bool TestTimer::IsActive()
{
    return active.load();
}

void TestTimer::StartOnce(int TimerDurationInMS)
{
    if (!active.load())
    {
        if (thread.joinable())
        {
            thread.join();
        }
        timer_duration = TimerDurationInMS;
        active.store(true);
        thread = std::thread(&TestTimer::timer_func, this);
    }
    else
    {
        Stop();
        StartOnce(TimerDurationInMS);
    }
}

void TestTimer::Stop()
{
    if (active.load())
    {
        std::lock_guard<std::mutex> _{ mtx };
        active.store(false);
        cv.notify_one();
    }
}

错误是从我的代码块中抛出的: thread = std::thread(&TestTimer::timer_func, this); 在第二次执行期间。

具体来说,错误是从 move_thread 函数引发的:_Thr = _Other._Thr;

thread& _Move_thread(thread& _Other)
        {   // move from _Other
        if (joinable())
            _XSTD terminate();
        _Thr = _Other._Thr;
        _Thr_set_null(_Other._Thr);
        return (*this);
        }

    _Thrd_t _Thr;
    }; 

这是一个例外:Unhandled exception at 0x76ED550B (ucrtbase.dll) in Sandbox.exe: Fatal program exit requested.

堆栈跟踪:

thread::move_thread(std::thread &_Other)
thread::operator=(std::thread &&_Other)
TestTimer::StartOnce(int TimerDurationInMS)

标签: multithreadingc++11

解决方案


如果只是测试

  1. 确保在调用析构函数时线程处理程序为空或加入。
  2. 使可以从多个线程访问的所有内容线程安全(特别是读取active标志)。简单地让它成为一个std::atomic_flag应该做的事情。

看起来你正在杀死一个指向活动线程的线程句柄,但是如果没有看到整个应用程序就很难说。

如果不是测试

...然后通常,当需要一个计时器时,无论是否重复,您都可以将alarm()信号安排到自身中。您仍然是完全单线程的,甚至不需要与pthread库链接。这里的例子。

并且当期望需要更多计时器并保持一段时间时,值得将一个实例boost::asio::io_service(或者asio::io_service如果您需要一个无增强的仅标头版本)放入您的应用程序中,该应用程序具有成熟的生产就绪计时器支持。这里的例子。


推荐阅读