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

Correct way to pause & resume an std::thread

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

StartMyThread() {

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

thread_running 是在 class header 中声明的 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++ 代码用于 iOS、Android、OS X 和 Windows。我的应用程序 UI 有一个按钮,需要我在按下按钮时启动和停止线程;该按钮在某些场合可以频繁使用。在停止或启动线程时,我可以在 UI 中看到一瞬间的延迟。

我的问题是: 在 C++ 中,这是经常 start/stop 线程的正确方法吗? 我认为按照这个逻辑,我正在创建一个新线程 every-time。据我了解,创建一个新线程会使 OS 分配很多新资源,这些资源可以是 time-consoming。我认为这是我犯的错误。我怎样才能避免这种情况?

如何在整个应用程序生命周期中使用同一个线程而不重复分配新线程,并且只在需要时 play/pause 它?

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

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