创建新线程导致异常

时间:2018-09-17 13:49:24

标签: multithreading c++11

我有一个计时器,它将创建一个新线程并等待计时器到期,然后再调用notify函数。它在第一次执行期间可以正常工作,但是在第二次启动计时器时,会尝试创建新线程时引发异常。 调试输出显示,在尝试创建新线程之前,先前的线程已退出。

Timer.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;
};

Timer.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)

2 个答案:

答案 0 :(得分:2)

如果只是测试

  1. 在调用析构函数时,请确保线程处理程序is empty or joined
  2. 确保可以从多个线程访问的所有内容都是线程安全的(特别是,读取active标志)。只需将其设置为std::atomic_flag即可。

看来您正在杀死指向活动线程的线程句柄,但是很难看到整个应用程序。

如果不是测试

...然后,通常,当需要单个计时器(是否重复)时,您可以自行安排一个alarm()信号。您可以保持完美的单线程状态,甚至不需要与pthread库链接。示例here

并且当期望需要更多的计时器并保持一点时间时,值得将boost::asio::io_service的实例(如果需要无增强的纯标题版本,可以将asio::io_service的实例删除)具有成熟的生产就绪计时器支持的应用程序。示例here

答案 1 :(得分:1)

您创建TestTimer并通过TestTimer::StartOnce第一次运行它,在此创建线程(在该行,稍后将引发异常)。线程完成后,它将在active = false;中设置timer_func
然后,您第二次致电TestTimer::StartOnce。与active == false一样,当前线程上不会调用Stop(),因此您将继续在thread = std::thread(&TestTimer::timer_func, this);中创建一个新线程。

然后出现大的但是
创建第二个线程之前,您尚未加入第一个线程。这就是它引发异常的原因。