попеременно запущенные потоки + ожидание нескольких потоков - PullRequest
0 голосов
/ 17 марта 2019

Это мой первый вопрос, поэтому, если я не достаточно точен, скажите мне, и я попытаюсь уточнить.

Рассмотрим следующую программу:

У меня одинаково много потоков двух функций void a() и void i().

Каждый поток a() выполняет некоторое вычисление для другого набора данных в цикле, а соответствующий поток i() выполняет другое вычисление для тех же данных (снова в цикле).

Функции a() и i() должны выполняться поочередно, но a() должен ждать завершения всех потоков i() (один цикл цикла), прежде чем он должен возобновиться. Каждая нить i() должна только ждать, пока соответствующая нить a() не закончит вычисления.

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

Я знаком с переменными и блокировками условий стандартной библиотеки. Тем не менее, я не знаю, как добиться поведения, описанного выше.

Я попробовал это с небольшой тестовой программой, которая только распечатывает данные, но вывод не тот, который должен быть.

Тест-программа:

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

Вывод должен выглядеть примерно так:

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
...

т.е. подтверждение того, что все потоки запущены, затем каждая нить a() перед соответствующей нитью i() (для каждого шага; до достижения N).

Вместо этого я получаю это:

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

Как я мог реализовать это / где моя ошибка?

Спасибо, что уделили время!

...