Skip to content

Commit

Permalink
Revert shared ptr, KISS
Browse files Browse the repository at this point in the history
  • Loading branch information
MeijisIrlnd committed Oct 1, 2024
1 parent 5b688c1 commit 2855019
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 72 deletions.
11 changes: 10 additions & 1 deletion source/utils/mostlyharmless_TaskThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@
#include <cassert>
#include <thread>
namespace mostly_harmless::utils {
TaskThread::~TaskThread() noexcept {
while (m_threadAboutToStart || isThreadRunning()) {
signalThreadShouldExit();
wake();
}
}

void TaskThread::perform() {
if (m_isThreadRunning) return;
m_threadAboutToStart = true;
if (!action) {
assert(false);
return;
}
auto actionWrapper = [this]() -> void {
m_threadAboutToStart.store(false);
m_isThreadRunning.store(true);
action();
m_isThreadRunning.store(false);
Expand All @@ -28,8 +37,8 @@ namespace mostly_harmless::utils {
}

void TaskThread::wake() {
std::lock_guard<std::mutex> guard{ m_mutex };
m_canWakeUp = true;
std::lock_guard<std::mutex> guard{ m_mutex };
m_conditionVariable.notify_one();
}

Expand Down
117 changes: 68 additions & 49 deletions tests/utils/mostlyharmless_TaskThreadTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,72 @@
#include <mostly_harmless/utils/mostlyharmless_TaskThread.h>
#include <mutex>
#include <thread>
#include <iostream>
namespace mostly_harmless::testing {
// TEST_CASE("Test TaskThread") {
// std::mutex mutex;
// mostly_harmless::utils::TaskThread taskThread;
// SECTION("Wait for lock") {
// auto x{ false };
// auto task = [&mutex, &x]() -> void {
// std::scoped_lock<std::mutex> sl{ mutex };
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
// x = true;
// };
// taskThread.action = std::move(task);
// taskThread.perform();
// // give it a bit of time to spin up.. (remember that this is a syscall)
// std::this_thread::sleep_for(std::chrono::milliseconds(5));
// REQUIRE(taskThread.isThreadRunning());
// // Sleep for a ms so the task has a chance to acquire the mutex..
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// std::scoped_lock<std::mutex> sl{ mutex };
// REQUIRE(x);
// REQUIRE(!taskThread.isThreadRunning());
// }
//
// SECTION("Kill") {
// auto task = [&taskThread]() -> void {
// while(!taskThread.threadShouldExit());
// };
// taskThread.action = std::move(task);
// taskThread.perform();
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// REQUIRE(taskThread.isThreadRunning());
// taskThread.signalThreadShouldExit();
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// REQUIRE(!taskThread.isThreadRunning());
// }
//
// SECTION("Sleep/Wake") {
// auto task = [&taskThread]() -> void {
// taskThread.sleep();
// };
// taskThread.action = std::move(task);
// taskThread.perform();
// std::this_thread::sleep_for(std::chrono::milliseconds(10));
// REQUIRE(taskThread.isThreadRunning());
// taskThread.wake();
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// REQUIRE(!taskThread.isThreadRunning());
// }
// }
}
TEST_CASE("Test TaskThread") {
std::mutex mutex;
mostly_harmless::utils::TaskThread taskThread;
SECTION("Wait for lock") {
auto x{ false };
auto task = [&mutex, &x]() -> void {
std::scoped_lock<std::mutex> sl{ mutex };
std::this_thread::sleep_for(std::chrono::milliseconds(10));
x = true;
};
taskThread.action = std::move(task);
taskThread.perform();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
REQUIRE(taskThread.isThreadRunning());
// Sleep for a ms so the task has a chance to acquire the mutex..
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::scoped_lock<std::mutex> sl{ mutex };
REQUIRE(x);
REQUIRE(!taskThread.isThreadRunning());
}

SECTION("Kill") {
auto task = [&taskThread]() -> void {
while (!taskThread.threadShouldExit())
;
};
taskThread.action = std::move(task);
taskThread.perform();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
REQUIRE(taskThread.isThreadRunning());
taskThread.signalThreadShouldExit();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
REQUIRE(!taskThread.isThreadRunning());
}

SECTION("Sleep/Wake") {
auto task = [&taskThread]() -> void {
taskThread.sleep();
};
taskThread.action = std::move(task);
taskThread.perform();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
REQUIRE(taskThread.isThreadRunning());
taskThread.wake();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
REQUIRE(!taskThread.isThreadRunning());
}

SECTION("Out of scope") {
std::chrono::time_point<std::chrono::steady_clock> start;
{
utils::TaskThread scopedThread;
auto task = [&scopedThread]() -> void {
while (!scopedThread.threadShouldExit()) {
scopedThread.sleep();
}
};
scopedThread.action = std::move(task);
scopedThread.perform();
start = std::chrono::steady_clock::now();
}
const auto end = std::chrono::steady_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
REQUIRE(duration < std::chrono::milliseconds(5));
}
}
} // namespace mostly_harmless::testing
45 changes: 23 additions & 22 deletions tests/utils/mostlyharmless_TimerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,39 @@
namespace mostly_harmless::tests {
TEST_CASE("Test Timer") {
mostly_harmless::utils::Timer timer;
// SECTION("Test calls") {
// std::atomic<int> callCount{ 0 };
// auto start = std::chrono::steady_clock::now();
// auto timerCallback = [&callCount, &start]() -> void {
// const auto now = std::chrono::steady_clock::now();
// const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
// // normalise, and truncate..
// const auto normalisedDelta = static_cast<double>(delta.count()) / 100.0;
// const auto truncatedDelta = std::round(normalisedDelta);
// REQUIRE(truncatedDelta == 1);
// start = std::chrono::steady_clock::now();
// ++callCount;
// };
// timer.setAction(std::move(timerCallback));
// timer.run(static_cast<int>(100));
// while (callCount < 5)
// ;
// timer.stop();
// REQUIRE(callCount >= 5);
// }
SECTION("Test calls") {
std::atomic<int> callCount{ 0 };
auto start = std::chrono::steady_clock::now();
auto timerCallback = [&callCount, &start]() -> void {
const auto now = std::chrono::steady_clock::now();
const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
// normalise, and truncate..
const auto normalisedDelta = static_cast<double>(delta.count()) / 100.0;
const auto truncatedDelta = std::round(normalisedDelta);
REQUIRE(truncatedDelta == 1);
start = std::chrono::steady_clock::now();
++callCount;
};
timer.action = std::move(timerCallback);
timer.run(static_cast<int>(100));
while (callCount < 5)
;
timer.stop();
REQUIRE(callCount >= 5);
}

SECTION("Test out-of-scope timer") {
std::atomic<int> count{ 0 };
{
mostly_harmless::utils::Timer scopedTimer;
auto task = [&count]() -> void {
++count;
};
scopedTimer.setAction(std::move(task));
scopedTimer.action = std::move(task);
scopedTimer.run(1);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
REQUIRE(count != 0);
REQUIRE(count == 0);
}
}
} // namespace mostly_harmless::tests

0 comments on commit 2855019

Please sign in to comment.