0

This is my first question here, so if I am not precise enough, tell me and I will try to elaborate.

Consider the following program:

I have equally many threads of two functions void a() and void i().

Each thread of a() performs some calculation on a different set of data in a loop and the corresponding thread of i() performs another calculation on the same data (again in a loop).

The functionsa() and i() have to run alternately, but a() has to wait for all threads of i() to finish (one cycle of the loop), before it is supposed to resume. Every thread of i() only has to wait until the corresponding thread of a() finished the calculation.

void a(int N, datatype data){
   for (int j = 0; j != N; j++){
      //wait until all threads of i() are finished
      //calculate something with data
      //notify i()
      }
   }

void i(int N, datatype data){
       for (int j = 0; j != N; j++){
          //wait until corresponding thread of a() is finished
          //calculate something with data
          //notify a()
          }
       }

I am familiar with the standard-library's condition variables and locks. Still, I do not know, how to achieve the behaviour described above.

I tried it with a little test-program, which only prints out data, but the output is not what it is supposed to be.

The test-program:

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

using namespace std;

const int O = 2;
const int N = 2;
mutex m, n;
condition_variable a_finished[O];
condition_variable i_finished;
bool i_done[O];


bool check(bool* b){
  bool tmp = true;
  for (int j = 0; j != O; j++){
    if (b[j] == false){
      return false;
    }
  }
  return true;
}

void printR(const char* c, int p){
  lock_guard<mutex> lockg(n);
  cout << c << p << " running!\n";
}

void print(int j, const char* c, int p){
  lock_guard<mutex> lockg(n);
  cout << c << p << ": " << j << "\n";
}

void a(int N, int p){
  printR("a", p);

  for (int j = 0; j != N; j++){
    unique_lock<mutex> lock(m);
    i_finished.wait(lock, [&](){return check(i_done); });
    //cout << check(i_done) << "\n";
    print(j, "a", p);
    lock.unlock();
    a_finished[p].notify_all();
  }
}

void i(int N, int p){
  printR("i", p);
  i_done[p] = true;
  for (int j = 0; j != N; j++){
    unique_lock<mutex> lock(m);
    a_finished[p].wait(lock);
    i_done[p] = false;
    print(j, "i", p);
    i_done[p] = true;
    lock.unlock();

    i_finished.notify_all();
  }
}



int main() {

  for (int c = 0; c != O; c++){
    i_done[c] = false;
  }

  thread a_threads[O];
  thread i_threads[O];

  for (int c = 0; c != O; c++){
    a_threads[c] = thread(a, N, c);
    i_threads[c] = thread(i, N, c);
  }
  this_thread::sleep_for(chrono::seconds(2));
  i_finished.notify_all();

  for (int c = 0; c != O; c++){
    a_threads[c].join();
    i_threads[c].join();
  }
}

The output should be something like:

i0 running!
a0 running!
i1 running!
a1 running!
a0: 0
a1: 0
i0: 0
i1: 0
a1: 1
i1: 1
a0: 1
i0: 1
a1: 2
a0: 2
i0: 2
i1: 2
...

i.e. the confirmation that all threads are running, then each thread of a() before the corresponding thread of i() (for every step; until N is reached).

Instead, I get this:

a0 running!
i0 running!
a1 running!
i1 running!
a1: 0
a1: 1
i1: 0
a0: 0
a0: 1
i0: 0

How could I implement this / where is my mistake?

Thank you for your time!

eumpf
  • 1
  • 1
  • It would be nice if the code you posted compiled. – Paul Sanders Mar 17 '19 at 18:06
  • "`f2` has to wait for corresponding `f1`" part is easiest to implement by having `f1` perform both calculations, one after another; since they must be sequential, there is no reason to have them in different threads. "All computations have to complete before starting a new cycle" part calls for a [synchronization barrier](https://stackoverflow.com/questions/38999911/what-is-the-best-way-to-realize-a-synchronization-barrier-between-threads) – Igor Tandetnik Mar 17 '19 at 18:36
  • fixed it to compile @PaulSanders – eumpf Mar 17 '19 at 18:47

0 Answers0