[fit][tests] Use std::thread in tests instead of std::async.
It turns out that std::async wasn't actually creating threads
so we weren't actually testing concurrent behavior. Now we are.
Test: fit-test
Change-Id: I17c4942f0b11435e69ae43aa992ed0d250dded12
diff --git a/system/utest/fit/examples/utils.cpp b/system/utest/fit/examples/utils.cpp
index 96b1e21..ae11061 100644
--- a/system/utest/fit/examples/utils.cpp
+++ b/system/utest/fit/examples/utils.cpp
@@ -9,7 +9,6 @@
// You do not need to include these headers just to use |fit::promise|
// or |fit::future|.
#include <chrono>
-#include <future>
#include <thread>
namespace utils {
@@ -26,10 +25,10 @@
}
void resume_in_a_little_while(fit::suspended_task task) {
- std::async(std::launch::async, [task]() mutable {
+ std::thread([task]() mutable {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
task.resume_task();
- });
+ }).detach();
}
} // namespace utils
diff --git a/system/utest/fit/sequencer_tests.cpp b/system/utest/fit/sequencer_tests.cpp
index 6b74312..13161a2 100644
--- a/system/utest/fit/sequencer_tests.cpp
+++ b/system/utest/fit/sequencer_tests.cpp
@@ -4,9 +4,10 @@
#include <unistd.h>
-#include <future> // for std::async
#include <string>
+#include <thread>
+#include <lib/fit/bridge.h>
#include <lib/fit/sequencer.h>
#include <lib/fit/single_threaded_executor.h>
#include <unittest/unittest.h>
@@ -86,19 +87,30 @@
uint64_t run_count = 0;
// Schedule work from a few threads, just to show that we can.
- for (int i = 0; i < 4; i++) {
- std::async(std::launch::async, [&]() mutable {
- for (int j = 0; j < 100; j++) {
- executor.schedule_task(
- fit::make_promise([&] { run_count++; }).wrap_with(seq));
- sleep(0);
- }
- });
+ constexpr int num_threads = 4;
+ constexpr int num_tasks_per_thread = 100;
+ std::thread threads[num_threads];
+ for (int i = 0; i < num_threads; i++) {
+ fit::bridge bridge;
+ threads[i] =
+ std::thread([&, completer = std::move(bridge.completer())]() mutable {
+ for (int j = 0; j < num_tasks_per_thread; j++) {
+ executor.schedule_task(
+ fit::make_promise([&] { run_count++; }).wrap_with(seq));
+ usleep(1);
+ }
+ completer.complete_ok();
+ });
+ executor.schedule_task(bridge.consumer().promise());
}
// Run the tasks.
executor.run();
- EXPECT_EQ(4 * 100, run_count);
+ for (int i = 0; i < num_threads; i++)
+ threads[i].join();
+
+ // We expect all tasks to have run.
+ EXPECT_EQ(num_threads * num_tasks_per_thread, run_count);
END_TEST;
}
diff --git a/system/utest/fit/single_threaded_executor_tests.cpp b/system/utest/fit/single_threaded_executor_tests.cpp
index 61bf469..cac5618 100644
--- a/system/utest/fit/single_threaded_executor_tests.cpp
+++ b/system/utest/fit/single_threaded_executor_tests.cpp
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <future> // for std::async
+#include <thread>
#include <lib/fit/defer.h>
#include <lib/fit/single_threaded_executor.h>
@@ -48,7 +48,6 @@
fit::single_threaded_executor executor;
uint64_t run_count[5] = {};
uint64_t resume_count[5] = {};
- uint64_t resume_count4b = 0;
// Schedule a task that suspends itself and immediately resumes.
executor.schedule_task(fit::make_promise([&](fit::context& context)
@@ -79,10 +78,10 @@
-> fit::result<> {
if (++run_count[2] == 100)
return fit::ok();
- std::async(std::launch::async, [&, s = context.suspend_task()]() mutable {
+ std::thread([&, s = context.suspend_task()]() mutable {
resume_count[2]++;
s.resume_task();
- });
+ }).detach();
return fit::pending();
}));
@@ -101,14 +100,16 @@
-> fit::result<> {
if (++run_count[4] == 100)
return fit::ok();
- std::async(std::launch::async, [&, s = context.suspend_task()]() mutable {
- resume_count[4]++;
+
+ // Race two threads to resume the task. Either can win.
+ // This is safe because these threads don't capture references to
+ // local variables that might go out of scope when the test exits.
+ std::thread([s = context.suspend_task()]() mutable {
s.resume_task();
- });
- std::async(std::launch::async, [&, s = context.suspend_task()]() mutable {
- resume_count4b++; // use a different variable to avoid data races
+ }).detach();
+ std::thread([s = context.suspend_task()]() mutable {
s.resume_task();
- });
+ }).detach();
return fit::pending();
}));
@@ -123,8 +124,6 @@
EXPECT_EQ(1, run_count[3]);
EXPECT_EQ(0, resume_count[3]);
EXPECT_EQ(100, run_count[4]);
- EXPECT_EQ(99, resume_count[4]);
- EXPECT_EQ(99, resume_count4b);
END_TEST;
}
@@ -160,7 +159,7 @@
[&, d = fit::defer([&] { destruction[2]++; })](fit::context& context)
-> fit::result<> {
run_count[2]++;
- std::async(std::launch::async, [s = context.suspend_task()] {});
+ std::thread([s = context.suspend_task()] {}).detach();
return fit::pending();
}));