英特尔 TBB 程序不终止,可能滥用参考计数器
Intel TBB program does not terminate, possible misuuse of reference counter
我有以下 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可能开始也可能结束,没关系。
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()
的操作有关。任何有助于理解问题的指示都会有所帮助。谢谢
问题出在异步任务附近。当 Task 5 完成时,它会向 Task 4 发出信号以将其引用计数递减至零,并且 Task 4 再次 运行。所以,有一个循环。因此,它会导致任务 3 的引用计数竞争,从而导致额外的循环。对于异步模式,您需要使用连续传递方法。
但是,我建议使用几种 tbb::task_group
算法来简化同步问题。
我有以下 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可能开始也可能结束,没关系。
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()
的操作有关。任何有助于理解问题的指示都会有所帮助。谢谢
问题出在异步任务附近。当 Task 5 完成时,它会向 Task 4 发出信号以将其引用计数递减至零,并且 Task 4 再次 运行。所以,有一个循环。因此,它会导致任务 3 的引用计数竞争,从而导致额外的循环。对于异步模式,您需要使用连续传递方法。
但是,我建议使用几种 tbb::task_group
算法来简化同步问题。