【问题标题】:Creating new thread causing exception创建新线程导致异常
【发布时间】:2018-09-17 13:49:23
【问题描述】:

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

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(&amp;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)

【问题讨论】:

  • 谢谢汉斯,来自 C 我有一点要学习正确的 C++ 类构造。我明确删除了“特殊”成员函数并编辑了我的帖子以包含修改后的标题。尽管这根本没有改变堆栈跟踪。堆栈跟踪已添加到帖子中。
  • 请注意,上面的代码已经过编辑以包含对问题的修复,特别是在尝试创建新线程之前未能加入线程。

标签: multithreading c++11


【解决方案1】:

如果只是测试

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

您似乎正在杀死一个指向活动线程的线程句柄,但如果不查看整个应用程序就很难说。

如果不是测试

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

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

【讨论】:

  • 是的 alarm() 会很完美,但不幸的是,这个应用程序需要使用 MSVC 构建[抱歉不包括标签]。
  • @BobbyTables - 那么我完全会选择ASIO(或Boost.ASIO)。
  • 谢谢 bobah,我下次试试。
  • 没有问题...或者来自 ASIO 作者的最新标准提案参考实现 - github.com/chriskohlhoff/executors :-)
  • 我将不得不坚持使用 boost,因为我的所有库都必须经过“审查”,但是 boost 实现应该可以工作,只是等待它解压,然后我才能尝试。
【解决方案2】:

您创建TestTimer 并第一次通过TestTimer::StartOnce 运行它,在那里您创建一个线程(在该行,稍后会引发异常)。当线程完成时,它会将active = false; 设置为timer_func
然后你第二次拨打TestTimer::StartOnce。由于active == falseStop() 不会在当前线程上调用,您继续在thread = std::thread(&amp;TestTimer::timer_func, this); 中创建一个新线程。

然后是大但是
在创建第二个线程之前,您还没有加入第一个线程。这就是它抛出异常的原因。

【讨论】:

  • 第一个线程正在终止。如果我尝试加入线程,我也会收到异常,因为线程已经退出。
  • @BobbyTables 你还必须加入一个已经终止的线程。你得到哪个例外?此外,在使用 join 之前,您应该检查线程是否可连接。
  • 我终于得到了正确的符号来加载。当我尝试加入线程时抛出的异常是:if (get_id() == _STD this_thread::get_id())_Throw_Cpp_error(_RESOURCE_DEADLOCK_WOULD_OCCUR);,这意味着我正在尝试从线程内部加入它......哎呀。
  • 好的,只要我不尝试加入自己,在创建新主题之前加入主题即可解决问题;)编辑我的帖子以包含最终版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-24
  • 1970-01-01
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
  • 2014-10-04
  • 2013-02-14
相关资源
最近更新 更多