lundi 27 septembre 2021

Implementing a "temporarily suspendable" concurrent loop in C++

I'm writing a program whose main thread spawns a worker thread that performs some work, sleeps for a set amount of time in an infinite loop, i.e. the worker thread executes:

void do_work() {
  for (;;) {
    // do some work
    
    std::this_thread::sleep_for(100ms);
  }
}

Now, I would additionally like to be able to temporarily completely disable this worker thread from the main thread, i.e. I would like to write the following functions:

  • disable_worker(): disable the worker thread
  • enable_worker(): enable the worker thread again

What I've come up with is the following:

#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>

using namespace std::literals::chrono_literals;

bool enabled;
std::mutex mtx;
std::condition_variable cond;

void disable_worker() {
  std::lock_guard<std::mutex> lock(mtx);
  enabled = false;
}

void enable_worker() {
  {
    std::lock_guard<std::mutex> lock(mtx);
    enabled = true;
  }

  cond.notify_one();
}

void do_work() {
  for (;;) {
    std::unique_lock<std::mutex> lock(mtx);
    cond.wait(lock, []{ return enabled; });

    // ... do some work ...

    std::this_thread::sleep_for(100ms);
  }
}


int main() {
  std::thread t(do_work);

  // ... enable/disable t as necessary ...
}

I suppose this works (at least I can't spot any issues), however, I would also like to guarantee that when either of enable_worker and disable_worker return (in the main thread), the working thread is guaranteed to be either blocking on the condition variable or sleeping, i.e. not performing any work. How can I implement this without any race conditions?

Aucun commentaire:

Enregistrer un commentaire