Программа Intel TBB не прекращается, возможно неправильное использование счетчика ссылок - PullRequest
0 голосов
/ 21 июня 2020

У меня есть следующий фрагмент кода TBB. Код не работает должным образом.

#include <iostream>
#include <tbb/mutex.h>
#include <tbb/tbb.h>

using namespace std;
using namespace tbb;

tbb::mutex printLock;

class Task1 : public task {
public:
  task* execute() {
    printLock.lock();
    cout << "Task 1 start" << std::endl;
    printLock.unlock();

    printLock.lock();
    cout << "Task 1 end" << std::endl;
    printLock.unlock();

    return NULL;
  }
};

class Task2 : public task {
public:
  task* execute() {
    printLock.lock();
    cout << "Task 2 start" << std::endl;
    printLock.unlock();

    printLock.lock();
    cout << "Task 2 end" << std::endl;
    printLock.unlock();

    return NULL;
  }
};

class Task5 : public task {
public:
  task* execute() {
    printLock.lock();
    std::cout << "Task 5 start" << std::endl;
    printLock.unlock();

    printLock.lock();
    std::cout << "T5:Sleep start" << std::endl;
    printLock.unlock();
    sleep(10);
    printLock.lock();
    std::cout << "T5:Sleep end" << std::endl;
    printLock.unlock();

    printLock.lock();
    std::cout << "Task 5 end" << std::endl;
    printLock.unlock();

    return NULL;
  }
};

class Task4 : public task {
public:
  task* execute() {
    printLock.lock();
    std::cout << "Task 4 start" << std::endl;
    printLock.unlock();

    set_ref_count(1); // Create a child but do not want to wait

    task& u = *new (task::allocate_child()) Task5();
    task::spawn(u);

    // task::wait_for_all(); // Task 5 is asynchronous, just to print

    printLock.lock();
    std::cout << "Task 4 end" << std::endl;
    printLock.unlock();

    return NULL;
  }
};

class Task3 : public task {
public:
  task* execute() {
    printLock.lock();
    std::cout << "Task 3 start" << std::endl;
    printLock.unlock();

    set_ref_count(2);

    task& u = *new (task::allocate_child()) Task4();
    task::spawn(u);

    task::wait_for_all();

    printLock.lock();
    std::cout << "Task 3 end" << std::endl;
    printLock.unlock();

    return NULL;
  }
};

class Root1 : public task {
public:
  task* execute() {
    printLock.lock();
    std::cout << "Root1 start" << std::endl;
    printLock.unlock();

    set_ref_count(4);

    task& a = *new (task::allocate_child()) Task1();
    task& v = *new (task::allocate_child()) Task3();
    task& b = *new (task::allocate_child()) Task2();

    task::spawn(a);
    task::spawn(v);
    task::spawn(b);

    task::wait_for_all();

    printLock.lock();
    std::cout << "Root1 end" << std::endl;
    printLock.unlock();

    return NULL;
  }
};

int main() {
  task& v = *new (task::allocate_root()) Root1();
  task::spawn_root_and_wait(v);
  return EXIT_SUCCESS;
}

Я ожидаю увидеть следующий (или аналогичный) результат. Задача 5 может начаться, может закончиться sh, это не имеет значения.

Root 1 start 
Task 2 start
Task 2 end
Task 3 start
Task 4 start
Task 4 end
Task 3 end
Task 5 start
T5:Sleep start
Task 1 start
Task 1 end
T5:Sleep end
Task 5 end
Root 1 end

Однако код может работать бесконечно (?) С повторением задач 3, 4 и 5.

Root 1 start
Task 2 start
Task 2 end
Task 3 start
Task 4 start
Task 4 end
Task 3 end
Task 5 start
T5:Sleep start
Task 1 start
Task 1 end
T5:Sleep end
Task 5 end
Task 4 start
Task 4 end
Task 3 start
Task 4 start
Task 4 end
Task 5 start
T5:Sleep start
Task 5 start
T5:Sleep start
Task 5 start
T5:Sleep start
T5:Sleep end
Task 5 end
Task 4 start
Task 4 end
Task 5 start
T5:Sleep start
T5:Sleep end
T5:Sleep end
Task 5 end
Task 5 start
Task 5 end
Task 4 start
Task 4 end
Task 5 start
T5:Sleep start
Task 5 start
T5:Sleep start
T5:Sleep start
^C

Я не понимаю пример полностью, возможно ошибка связана с манипуляцией с set_ref_count(). Любые указатели, которые помогут понять проблему, помогут. Спасибо.

1 Ответ

0 голосов
/ 22 июня 2020

Проблема близка к асинхронной задаче. Когда задача 5 завершается, она сигнализирует задаче 4 об уменьшении числа ссылок, которое достигает нуля, и снова запускается задача 4. Итак, есть al oop. В результате это приводит к гонке на счетчике рефинансирования Задачи 3, что приводит к дополнительному l oop. Для асинхронного шаблона вам необходимо использовать подход передачи продолжения. Однако я бы рекомендовал использовать несколько алгоритмов tbb::task_group, чтобы просто решить проблемы с синхронизацией.

...