2015-11-26 1 views
1

Я пытаюсь понять задачи в intel tbb. Я пытаюсь создать параллельный алгоритм для решения lingfords paring для двух «блоков» L (2, n) (https://en.wikipedia.org/wiki/Langford_pairing)tbb-tasks не принимают заданный параметр

Мой алгоритм работает, когда я вызываю последовательный, но я хочу перевести его в задачи. Это то, что мой алгоритм должен сделать:

  • сделать вектор в размере 2 * п, INIT с «0»
  • для 0 Недо (1 + счётчика цикла + расстояния из-блоков) < размера вектора делать:
  • дублировать заданный вектор
  • добавить текущий блок на
  • счётчик цикла
  • добавить текущий блок 1 + + расстояние счётчик цикла-из-блоков
  • если это не последний блок:
  • сделать то же самое в задаче с блочной разницей -1 и дублируют уже заполненный вектор
  • еще, проверьте, есть ли «0» левый
  • , если нет, то это правильное решение

I в настоящее время игнорировать симметрию

Это текущий код

int langford_task (int step, vector<int> v) 
{ 
task_group g; 
int counter = 0; 

cout << "current step: "<< step << endl; 
cout << "current vector in task: "; 

printVector(v); 

//'1+var+step' == 1 + our loopcounter + the distance of two 'blocks' 
for (unsigned int var = 0; 1+var+step < v.size(); ++var) 
{ 

    if (v[ var ] == 0 && v[ 1+var+step ] == 0) 
    { 
     vector<int> recV = v; 
     recV[var] = step; 

     recV[1+var+step] = step; 

     cout << "recV = "; 
     printVector(recV); 
     if (step - 1 != 0) 
     { 
      //make a task with step -1 and the new filled vector 
      g.run([&]{ counter += langford_task(step-1, recV); }); //spawn a task 
     } 
     else 
     { 
      // if there is no "0" in our vector, we found a valid solution and return 1 
      if(!(std::find(recV.begin(), recV.end(), 0) != recV.end())) 
       return 1; 
     } 
    } 

} 
g.wait(); //wait for tasks 

return counter; 
} 

в теории task_group должна ждать в конце FOOR петли, так что все дети-задача s может закончиться первым.

напечатать вектор, так что я могу видеть то, что находится внутри, и то своего рода странным:

current step: 3 
current vector in task: [0, 0, 0, 0, 0, 0, ] 
recV = [3, 0, 0, 0, 3, 0, ] 
recV = [0, 3, 0, 0, 0, 3, ] 

все нормально, пока задача не приходит

current step: 2 
current vector in task: [28848976, 0, 0, 0, 0, 3, ] 
recV = [28848976, 2, 0, 0, 2, 3, ] 
current step: 1 

это совершенно странно. Я должен упомянуть, что «28848976» представляется случайным числом. Она всегда разная, большую часть времени его «0»

я ожидал для «текущего вектора в задаче:» в «текущем этапе: 2» -сече-

[3, 0, 0, 0, 3, 0, ] 

, потому что это просто параметр я отдал эту функцию.

Он «работает», когда я добавляю g.wait(); // Ожидает задачи

непосредственно под

g.run(...) 

но потребляет еще больше времени выполнения, то работать без задач на всех, и, вероятно, не параллельно больше.

current step: 3 
current vector in task: [0, 0, 0, 0, 0, 0, ] 
recV = [3, 0, 0, 0, 3, 0, ] 
current step: 2 
current vector in task: [3, 0, 0, 0, 3, 0, ] 
recV = [3, 0, 2, 0, 3, 2, ] 
current step: 1 
current vector in task: [3, 0, 2, 0, 3, 2, ] 
recV = [3, 1, 2, 1, 3, 2, ] 

Почему эта задача ведет себя так странно? Что я могу сделать, чтобы запустить его?

Просто для завершения, остальная часть кода:

void printVector(vector<int> v) 
{ 
    cout << "["; 
    for (unsigned int var = 0; var < v.size(); ++var) { 
     cout << v[var] << ", "; 
    } 
    cout << "]" << endl; 
} 


void langford_parallel(int s, int n) 
{ 
    cout << "berechne Langenford-Sequenz für S = " << s << " und N = " << n << endl; 

// concurrent_vector<int> v((s*n), 0); 
    vector<int> v((s*n), 0); 

    int solutions = 0; 
    solutions = langford_task(n, v); 

    cout << "found solutions: " << solutions << endl; 
} 

int main() 
{ 
    tick_count t0 = tick_count::now(); 
// langford_sequentiell(2, 12); 
    langford_parallel(2, 3); 
    tick_count t1 = tick_count::now(); 

    cout << "work took " << (t1-t0).seconds() << " seconds." << endl; 
    return 0; 
} 

ответ

1

Существует классический data race на общих counter, которые могут быть изменены параллельно разными задачами одновременно.

И recV ссылается вне сферы действия, потому что функция лямбда принимает его по ссылке и выполняется несинхронно в задаче.

если вы можете использовать , синтаксис лямбда расширяется, так что вы можете назначить в списке захвата:

g.run([&, V{std::move(recV)}]{ counter += langford_task(step-1, V); }); 

В противном случае, с использованием std::shared_ptr<> вокруг вектора для того, чтобы пройти по значению указателя, чтобы вектор не выходил за рамки:

std::shared_ptr<std::vector<int>> recV (new std::vector<int>(v)); 
//... 
g.run([&, recV]{ counter += langford_task(step-1, *recV); }); 
+0

Спасибо за ваш ответ. Я взял счетчик и не использовал tbb :: atomic globalCounter; Это не меняет того факта, что задачи получили [0, 0, 0, 0, 0, 3,] вместо [3, 0, 0, 0, 3, 0,] в качестве аргумента , Я загрузил измененные файлы в http://pastebin.com/xQtuVWpw – Rhiji

+0

Благодарим вас за улучшение ответа. Я постараюсь скоро это сделать > (голосование приветствуется;) Прошу прощения. Мне нужно «15 репутации», чтобы сделать это, и в настоящее время я получил 3. Я запомню, чтобы вы голосовали за свой ответ, как только я заработал 15 человек. – Rhiji

+0

Это: "" "std :: shared_ptr > recV = new std :: vector (v);" "" просто не компилируется. В Интернете нет ни одного примера хорошего использования, описывающего как std :: shared_ptr <> вокруг вектора. В этом случае компилятор g ++ жалуется на «Преобразование в нескалярный тип» – Rhiji

0

Я сделал ошибку с лямбда-функцией.

Как описано here, в моем случае использования [=] является правильным лямбда-параметра

g.run([=]{ counter += langford_task(step-1, recV); }); 

Это сделало выполнение работ проблемно-групп, как ожидалось.

Как сказал Антон, мне также необходимо избегать условий гонки в стойке. Я бы рано или поздно столкнулся с этим вопросом.

+0

Ну .. это не так, правильно с точки зрения производительности. Вы скопируете весь вектор сейчас вместо move-assigment, который является сложностью O (1) – Anton

+0

Как бы я сделал его более эффективным? – Rhiji