暂停和恢复 std::thread 的正确方法

Posted

技术标签:

【中文标题】暂停和恢复 std::thread 的正确方法【英文标题】:Correct way to pause & resume an std::thread 【发布时间】:2017-03-25 11:27:36 【问题描述】:

我在C++ 代码中使用std::thread 不断轮询某些数据并将其添加到缓冲区。我使用C++ lambda 像这样启动线程:

StartMyThread() 

    thread_running = true;
    the_thread = std::thread  [this] 
        while(thread_running) 
          GetData();
        
    ;

thread_running 是在类头中声明的atomic<bool>。这是我的GetData 函数:

GetData() 
    //Some heavy logic which needs to be executed in a worker thread

接下来我还有一个StopMyThread 函数,我将thread_running 设置为false,以便它退出lambda block 中的while 循环。

StopMyThread() 
  thread_running = false;
  the_thread.join();

效果很好。线程启动和停止而不会崩溃。

此 C++ 代码用于 iosandroid、OS X 和 Windows。我的应用程序 UI 有一个按钮,需要我在按下按钮时启动和停止线程;这个按钮在某些场合可以经常使用。在停止或启动线程时,我可以看到 UI 出现瞬间延迟。

我的问题是: 在 C++ 中,这是频繁启动/停止线程的正确方法吗? -时间。据我了解,创建一个新线程会使操作系统分配大量新资源,这可能是耗时的。我认为这是我正在做的错误。我怎样才能避免这种情况?

如何在应用程序生命周期内不重复分配新线程的情况下使用同一个线程,并在需要时播放/暂停它?

【问题讨论】:

延迟也可能是你在等待旧线程退出。 (如果你有两个线程使用相同的thread_running 值,你会很伤心!) 您可以通过让线程等待std::mutex 来暂停线程。 当心:请参阅 blogs.msdn.microsoft.com/oldnewthing/20031209-00/?p=41573 了解为什么通用 suspend_thread 函数不是一个好主意。 (示例是关于 Windows 上的 C#,但原则适用于任何地方。)如果您确实使用互斥锁使其等待,则必须仔细考虑阻塞 UI 线程。 std::mutex + std::condition_variableresume 函数只会执行 `notify_one 我知道这个问题很老了,但我只想指出,与计算机的速度相比,“按钮频繁按下”仍然非常缓慢。停止和启动线程。 【参考方案1】:

这是使用条件变量的经典示例。您等待互斥体并在满足特定条件时通知线程;这样你就不需要在需要时分配一个新线程,但这并不总是一件好事,如果你想节省内存。另一种方法是在需要数据时让一个协程让给另一个协程,这可以说是更漂亮的。需要自己实现协程,或者使用现成的库,比如boost.coroutine

示例

::std::condition_variable cv_;
::std::mutex m_;
bool data_is_ready_;

StartMyThread()

  ::std::thread([this]
    
      for (;;)
      
        ::std::unique_lock<decltype(m_)> l(m_);
        cv_.wait(l, [this] return data_is_ready_; );

        // do your stuff, m_ is locked
        data_is_ready_ = false;
      
    
  ).detach();

通知:


  ::std::unique_lock<decltype(m_)> l(m_);

  data_is_ready_ = true;


cv_.notify_one();

因为在通知之前释放锁通常比反之更快。

【讨论】:

你没有错过锁定线程内的互斥锁吗? cv.wait 不会锁定它,它需要一个 locked 互斥体,并会在等待期间 unlock 它。 挑剔。为什么要完全限定 std 命名空间?除非你做了一些讨厌和错误的事情,否则它是丑陋和无用的。 为什么最后使用.detach。这不会使它成为daemon 线程吗? 是的,这是一个分离的线程,但他知道join(),所以他可以做不同的事情。 最后一个问题所有参与者:thread_runningatomic&lt;bool&gt;,正如我在问题中所说的那样。如果thread_running 为假,我可以继续退出GetData()。并且只有在thread_running 为真时才执行完整的方法逻辑。这不是更有效吗?

以上是关于暂停和恢复 std::thread 的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

正确的线程调用语法?错误:没有匹配的调用 std::thread::thread(<brace-enclosed initializer list>)

关于java多线程如何正确暂停的理解

自动测试后安全清理阻塞的 std::thread

在情节提要之间暂停和恢复 CADisplayLink

c++11的std::thread能用类的成员函数构造一个线程吗?语法怎样?

暂停 jquery 倒计时按钮