Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dea5a35

Browse files
committed
updated unittest
1 parent 1442c23 commit dea5a35

File tree

5 files changed

+62
-28
lines changed

5 files changed

+62
-28
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ add_test(builder ${TF_UTEST_DIR}/taskflow -tc=Builder)
261261
add_test(creation ${TF_UTEST_DIR}/taskflow -tc=Creation)
262262
add_test(dispatch ${TF_UTEST_DIR}/taskflow -tc=Dispatch)
263263
add_test(multiple_runs ${TF_UTEST_DIR}/taskflow -tc=MultipleRuns)
264+
add_test(parallel_runs ${TF_UTEST_DIR}/taskflow -tc=ParallelRuns)
264265
add_test(parallel_for ${TF_UTEST_DIR}/taskflow -tc=ParallelFor)
265266
add_test(parallel_for_idx ${TF_UTEST_DIR}/taskflow -tc=ParallelForOnIndex)
266267
add_test(reduce ${TF_UTEST_DIR}/taskflow -tc=Reduce)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ The executor provides a rich set of methods to run a taskflow.
216216
You can run a taskflow one or multiple times, or until a stopping criteria is met.
217217
These methods are non-blocking and all return a [std::future][std::future]
218218
to let you query the execution status.
219+
All methods are *thread-safe*.
219220

220221
```cpp
221222
executor.run(taskflow); // run the taskflow once
@@ -527,7 +528,7 @@ tf::Task B = taskflow.emplace([] (tf::Subflow& subflow) {
527528

528529
A.precede(B);
529530

530-
executor.run(tf).get(); // run the taskflow
531+
executor.run(tf).wait(); // run the taskflow
531532
tf.dump(std::cout); // dump the graph including dynamic tasks
532533
```
533534

doxygen/releases/master-branch.dox

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ To download the newest version of Cpp-Taskflow, please clone from <a href="https
1919
@li Discovering a scalable memory allocator to handle the taskflow graph
2020
@li Adding more benchmarks to compare Cpp-Taskflow with OpenMP and TBB
2121
@li Improving the partition policy of parallel_for
22+
@li Making executor thread-safe
2223

2324
@section master-branch_bug_fixes Bug Fixes
2425

taskflow/core/executor.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// 2019/08/03 - modified by Tsung-Wei Huang
2+
// - made executor thread-safe
3+
//
14
// 2019/07/26 - modified by Chun-Xun Lin
25
// - Combine explore_task & wait_for_task
36
// - Remove CAS operations

unittest/taskflow.cpp

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -420,39 +420,67 @@ TEST_CASE("MultipleRuns" * doctest::timeout(300)) {
420420
// Testcase: ParallelRuns
421421
// --------------------------------------------------------
422422
TEST_CASE("ParallelRuns" * doctest::timeout(300)) {
423-
424-
for(size_t w=0; w<=32; ++w) {
425-
426-
tf::Executor executor(w);
427423

428-
std::atomic<int> counter = 0;
424+
std::atomic<int> counter;
425+
std::vector<std::thread> threads;
429426

430-
auto make_taskflow = [&] (tf::Taskflow& tf) {
431-
for(int i=0; i<1024; i++) {
432-
auto A = tf.emplace([&] () {
433-
counter.fetch_add(1, std::memory_order_relaxed);
434-
});
435-
auto B = tf.emplace([&] () {
436-
counter.fetch_add(1, std::memory_order_relaxed);
437-
});
438-
A.precede(B);
439-
}
440-
};
441-
442-
std::vector<std::thread> threads;
443-
for(int t=1; t<=32; t++) {
444-
threads.emplace_back([&] () {
445-
tf::Taskflow taskflow;
446-
make_taskflow(taskflow);
447-
executor.run(taskflow).wait();
427+
auto make_taskflow = [&] (tf::Taskflow& tf) {
428+
for(int i=0; i<1024; i++) {
429+
auto A = tf.emplace([&] () {
430+
counter.fetch_add(1, std::memory_order_relaxed);
448431
});
432+
auto B = tf.emplace([&] () {
433+
counter.fetch_add(1, std::memory_order_relaxed);
434+
});
435+
A.precede(B);
449436
}
437+
};
450438

451-
for(auto& t : threads) {
452-
t.join();
453-
}
439+
SUBCASE("RunAndWait") {
440+
for(size_t w=0; w<=32; ++w) {
441+
tf::Executor executor(w);
442+
counter = 0;
443+
for(int t=0; t<32; t++) {
444+
threads.emplace_back([&] () {
445+
tf::Taskflow taskflow;
446+
make_taskflow(taskflow);
447+
executor.run(taskflow).wait();
448+
});
449+
}
454450

455-
REQUIRE(counter.load() == 32*1024*2);
451+
for(auto& t : threads) {
452+
t.join();
453+
}
454+
threads.clear();
455+
456+
REQUIRE(counter.load() == 32*1024*2);
457+
}
458+
}
459+
460+
SUBCASE("RunAndWaitForAll") {
461+
for(size_t w=0; w<=32; ++w) {
462+
tf::Executor executor(w);
463+
counter = 0;
464+
std::vector<std::unique_ptr<tf::Taskflow>> taskflows(32);
465+
std::atomic<size_t> barrier(0);
466+
for(int t=0; t<32; t++) {
467+
threads.emplace_back([&, t=t] () {
468+
taskflows[t] = std::make_unique<tf::Taskflow>();
469+
make_taskflow(*taskflows[t]);
470+
executor.run(*taskflows[t]);
471+
++barrier; // make sure all runs are issued
472+
});
473+
}
474+
475+
while(barrier != 32);
476+
executor.wait_for_all();
477+
REQUIRE(counter.load() == 32*1024*2);
478+
479+
for(auto& t : threads) {
480+
t.join();
481+
}
482+
threads.clear();
483+
}
456484
}
457485

458486
}

0 commit comments

Comments
 (0)