-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |