Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to pause & resume an std::thread

I am using an std::thread in my C++ code to constantly poll for some data & add it to a buffer. I use a C++ lambda to start the thread like this:

StartMyThread() {

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

thread_running is an atomic<bool> declared in class header. Here is my GetData function:

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

Next I also have a StopMyThread function where I set thread_running to false so that it exits out of the while loop in the lambda block.

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

It works well. The thread starts & stops without crashing.

This C++ code is used on iOS, Android, OS X and Windows. My application UI has a button which requires me to start & stop the thread on a button press; this button can be frequently used in some occasions. I can see a split second delay in UI while stopping or starting the thread.

My question is: In C++, is this a correct way to start/stop a thread frequently ? I think that with this logic I am creating a new thread every-time. And as I understand, creating a new thread makes the OS allocate lot of new resources which can be time-consoming. And I think this is the mistake I am doing. How can I avoid this ?

How can make use of the same thread without allocating new one repeatedly throughout the application lifecycle, and just play/pause it when required ?

like image 440
TheWaterProgrammer Avatar asked Nov 11 '16 09:11

TheWaterProgrammer


People also ask

How do you create a pause?

a: Use punctuation (comma, ellipsis, dash) to indicate a pause or break. may be in the middle of a sentence or at the end of it. You can use commas, dashes, or ellipses to cue different types of pauses.

How do you pause a game in Unity?

To pause a game in Unity, simply set the time scale to zero to pause it and back to one (the default) to unpause it again.

How do you pause a Minecraft game?

The pause menu is one of Minecraft's multiple menu screens. Activated during gameplay, it provides a portal to configure game options, quit out of a world, and more. This menu can be accessed anytime by pausing the game with the Esc key by default.


1 Answers

This is the classical example for the use of a condition variable. You wait on a mutex and notify a thread when a certain condition is fulfilled; this way you don't need to allocate a new thread when you need one, but this is not always a good thing, if you wish to save memory. An alternative would be a coroutine yielding to another coroutine when data is needed, which is arguably prettier. You need to implement coroutines yourself, or use a ready-made library, such as boost.coroutine.

Example

::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();
}

To notify:

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

  data_is_ready_ = true;
}

cv_.notify_one();

As it is often faster to free the lock before notifying, than vice-versa.

like image 171
user1095108 Avatar answered Sep 28 '22 12:09

user1095108