Skip to content

Commit

Permalink
仮実装
Browse files Browse the repository at this point in the history
  • Loading branch information
idofront committed Nov 29, 2024
1 parent fc637b4 commit 90fca11
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/Thread/Employer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef THREAD__EMPLOYER_HPP
#define THREAD__EMPLOYER_HPP

#include <Thread/ThreadPool.hpp>
#include <thread>

namespace Thread
{
class Employer
{
public:
Employer() : _ThreadPool(std::thread::hardware_concurrency())
{
}

private:
ThreadPool _ThreadPool;
};
} // namespace Thread

#endif
47 changes: 47 additions & 0 deletions src/Thread/Future.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef THREAD__FUTURE_HPP
#define THREAD__FUTURE_HPP

#include <Thread/Runnable.hpp>
#include <memory>
#include <optional>

namespace Thread
{
class Future
{
public:
Future(std::shared_ptr<Runnable> runnablePtr) : _RunnablePtr(runnablePtr)
{
}
/// @brief Wait for the thread to finish
/// @param timeout
/// @return If the thread is not finished after the timeout, return false.
virtual bool Wait(std::chrono::milliseconds timeout)
{
// TODO: Implement the function
return false;
}

/// @brief Try to terminate the thread
virtual void TryTerminate()
{
_RunnablePtr->TryTerminate();
}

/// @brief Get the runnable object.
/// @return The runnable object if the thread is finished, otherwise return nullopt.
virtual std::optional<RunnableSharedPtr> Get(std::chrono::milliseconds timeout)
{
// Wait for the thread to finish
auto wait = Wait(std::chrono::milliseconds(timeout));

// If the thread is not finished after the timeout, return nullopt
return wait ? std::make_optional(_RunnablePtr) : std::nullopt;
}

private:
std::shared_ptr<Runnable> _RunnablePtr;
};
} // namespace Thread

#endif
67 changes: 67 additions & 0 deletions src/Thread/Runnable.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef THREAD__RUNNABLE_HPP
#define THREAD__RUNNABLE_HPP

#include <chrono>
#include <memory>

namespace Thread
{
class Runnable
{
public:
virtual void Run() final
{
PreTask();
while (IsContinue())
{
Task();
}
PostTask();
}
virtual void TryTerminate() final
{
// Change flag to terminate
_IsRequestedToTerminate = true;

// Interrupt the sleep if the thread is sleeping
}
virtual void Join()
{
// Wait for the thread to finish
}

protected:
virtual void Sleep(std::chrono::milliseconds duration)
{
// Sleep for the given duration, but should be interrupted if requested to terminate
}
virtual void PreTask()
{
// Do nothing by default
}
virtual void Task()
{
// TODO: Change to pure virtual function
}
virtual void PostTask()
{
// Do nothing by default
}

private:
bool _IsRequestedToTerminate;

bool IsContinue()
{
return !ShouldBeTerminated();
}
bool ShouldBeTerminated()
{
return _IsRequestedToTerminate;
}
};

using RunnableSharedPtr = std::shared_ptr<Runnable>;
} // namespace Thread

#endif
69 changes: 69 additions & 0 deletions src/Thread/ThreadPool.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <Thread/ThreadPool.hpp>

namespace Thread
{
ThreadPool::ThreadPool(std::size_t threadCount)
{
// Thread pool initialization
for (std::size_t i = 0; i < threadCount; i++)
{
_Threads.push_back(std::nullopt);
}
}

ThreadPool::~ThreadPool() = default;

std::optional<Future> ThreadPool::Submit(std::unique_ptr<Runnable> runnablePtr)
{
if (!runnablePtr)
{
return std::nullopt;
}

// Get lock for the thread pool
auto lock = std::lock_guard(_Mutex);

// Move the runnable to the local variable
auto moveRunnablePtr = std::move(runnablePtr);
runnablePtr = nullptr;

// Convert to shared pointer
auto sharedRunnablePtr = std::shared_ptr<Runnable>(moveRunnablePtr.release());

// Find an available thread
auto availableThreadIter = std::find_if(
_Threads.begin(), _Threads.end(), [](const std::optional<std::thread> &thread) { return !thread.has_value(); });

// No available thread
if (availableThreadIter == _Threads.end())
{
// Move the shared pointer back to the unique pointer
runnablePtr.reset(sharedRunnablePtr.get());
return std::nullopt;
}

// Assign the runnable to the thread
auto function = std::bind(&Runnable::Run, sharedRunnablePtr);
*availableThreadIter = std::thread(function);

// Return the future object
return Future(sharedRunnablePtr);
}

std::size_t ThreadPool::ActiveThreadCount() const
{
// Get lock for the thread pool
auto lock = std::lock_guard(_Mutex);

// Count the number of active threads
auto count = std::count_if(_Threads.begin(), _Threads.end(),
[](const std::optional<std::thread> &thread) { return thread.has_value(); });

return count;
}

std::size_t ThreadPool::ThreadCount() const
{
return _Threads.size();
}
}; // namespace Thread
38 changes: 38 additions & 0 deletions src/Thread/ThreadPool.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef THREAD__THREAD_POOL_HPP
#define THREAD__THREAD_POOL_HPP

#include <Thread/Future.hpp>
#include <algorithm>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>

namespace Thread
{
class ThreadPool
{
public:
ThreadPool(std::size_t threadCount);
virtual ~ThreadPool();

/// @brief Submit a runnable to the thread pool
/// @param runnablePtr
/// @return Future object to control the thread. If no thread is available, return nullopt.
virtual std::optional<Future> Submit(std::unique_ptr<Runnable> runnablePtr);

/// @brief Get the number of active threads
/// @return The number of active threads
virtual std::size_t ActiveThreadCount() const;

/// @brief Get the number of threads in the thread pool
virtual std::size_t ThreadCount() const;

private:
std::vector<std::optional<std::thread>> _Threads;
mutable std::mutex _Mutex;
};
} // namespace Thread

#endif

0 comments on commit 90fca11

Please sign in to comment.