Notify when all thread loops ended their iteration in main thread

58 Views Asked by At

I've the following code:

#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>
#include <vector>
#include <syncstream>

int main() {
  std::condition_variable myCV;
  std::mutex myMutex;
  bool isRunning{ true };

  const size_t numberOfThreads{ 6 };

  std::vector<std::jthread> threads;

  for (size_t i = 0; i < numberOfThreads; i++) {
    threads.emplace_back(
      [&isRunning, &myMutex, &myCV, i]() {
        std::unique_lock loopLock(myMutex);
        while (isRunning) {
          myCV.wait(loopLock);
          std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
        std::osyncstream oss{ std::cout };
        oss << "Ended thread " << i << std::endl;
      }
    );
  }


  for (int i = 0; i < 100; i++) {
    myCV.notify_all();
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    std::cout << "Test loop " << i << std::endl;
  }

  isRunning = false;
  myCV.notify_all();

  return 0;
}

The code instantiates some thread. Every thread has an internal infinite loop and the iteration starts when they're notified by the myCV condition variable.

The idea is to start the iteration, wait that all threads make their work, collect results (not shown here) and then start the next execution iteration.

My problem is that the main thread doesn't wait the end of all thread loop iterations before going ahead, and I don't know how to do it.

I've think about a solution like this one:

#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>
#include <vector>
#include <syncstream>
#include <atomic>

int main() {
  std::condition_variable myCV;
  std::mutex myMutex;
  bool isRunning{ true };

  std::condition_variable loopEndCV;
  std::atomic<size_t> threadCounter{ 0 };
  std::mutex loopEndMutex;

  const size_t numberOfThreads{ 6 };

  std::vector<std::jthread> threads;

  std::cout << "Instantiating threads..." << std::endl;

  for (size_t i = 0; i < numberOfThreads; i++) {
    threads.emplace_back(
      [&, i]() {
        std::unique_lock loopLock(myMutex);
        while (isRunning) {
          myCV.wait(loopLock);
          std::this_thread::sleep_for(std::chrono::milliseconds(500));
          --threadCounter;
          if (threadCounter.load() == 0) {
            loopEndCV.notify_one();
          }
        }
        std::osyncstream oss{ std::cout };
        oss << "Ended thread " << i << std::endl;
      }
    );
  }


  for (int i = 0; i < 100; i++) {
    threadCounter = numberOfThreads;
    myCV.notify_all();
    std::unique_lock loopEndLock(loopEndMutex);

    loopEndCV.wait(loopEndLock, [&threadCounter]() { return threadCounter.load() == 0; });
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    std::cout << "Test loop " << i << std::endl;
  }

  isRunning = false;
  myCV.notify_all();

  return 0;
}

Basically I've added another std::condition_variable, that should notify when all threads end their loop iteration, so the main thread wait for this and it can go ahead when all iterations has ended. But this blocks completely the program (I print only the string before the creation of threads), so I've some deadlock somewhere or some other type of error, and I cannot solve this.

What I'm doing wrong? How can I fix the code

0

There are 0 best solutions below