title: C++ Fork Join Parallelism Blocking
body: <p>Suppose you wish you run a section in parallel, then merge back into the main thread then back to section in parallel, and so on. Similar to the childhood game red light green light.</p>
  
  <p>I've given an example of what I'm trying to do, where I'm using a conditional variable to block the threads at the start but wish to start them all in parallel but then block them at the end so they can be printed out serially. The *= operation could be a much larger operation spanning many seconds. Reusing the threads is also important. Using a task queue might be too heavy.</p>
  
  <p>I need to use some kind of blocking construct that isn't just a plain busy loop, because I know how to solve this problem with busy loops.</p>
  
  <p>In English:</p>
  
  <ol>
  <li>Thread 1 creates 10 threads that are blocked</li>
  <li>Thread 1 signals all threads to start (without blocking eachother)</li>
  <li>Thread 2-11 process their exclusive memory</li>
  <li>Thread 1 is waiting until 2-11 are complete (can use an atomic to count here)</li>
  <li>Thread 2-11 complete, each can notify for 1 to check its condition if necessary </li>
  <li>Thread 1 checks its condition and prints the array</li>
  <li>Thread 1 resignals 2-11 to process again, continuing from 2</li>
  </ol>
  
  <p>Example code (Naive adapted from example on cplusplus.com):</p>
  
  <pre><code>// condition_variable example
  #include &lt;iostream&gt;           // std::cout
  #include &lt;thread&gt;             // std::thread
  #include &lt;mutex&gt;              // std::mutex, std::unique_lock
  #include &lt;condition_variable&gt; // std::condition_variable
  #include &lt;atomic&gt;
  
  std::mutex mtx;
  std::condition_variable cv;
  bool ready = false;
  std::atomic&lt;int&gt; count(0);
  
  bool end = false;
  int a[10];
  
  void doublea (int id) {
    while(!end) {
      std::unique_lock&lt;std::mutex&gt; lck(mtx);
      while (!ready) cv.wait(lck);
      a[id] *= 2;
      count.fetch_add(1);
    }
  }
  
  void go() {
    std::unique_lock&lt;std::mutex&gt; lck(mtx);
  
    ready = true;
    cv.notify_all();
    ready = false; // Naive
  
    while (count.load() &lt; 10) sleep(1);
    for(int i = 0; i &lt; 10; i++) {
      std::cout &lt;&lt; a[i] &lt;&lt; std::endl;
    }
  
    ready = true;
    cv.notify_all();
    ready = false;
    while (count.load() &lt; 10) sleep(1);
    for(int i = 0; i &lt; 10; i++) {
      std::cout &lt;&lt; a[i] &lt;&lt; std::endl;
    }
  
    end = true;
    cv.notify_all();
  }
  
  int main () {
    std::thread threads[10];
    // spawn 10 threads:
    for (int i=0; i&lt;10; ++i) {
      a[i] = 0;
      threads[i] = std::thread(doublea,i);
    }
  
    std::cout &lt;&lt; "10 threads ready to race...\n";
    go();                       // go!
  
    return 0;
  }
  </code></pre>