-
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
Colin S
committed
Dec 21, 2024
1 parent
027ba9f
commit a03a0aa
Showing
3 changed files
with
243 additions
and
26 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 |
---|---|---|
@@ -1,29 +1,39 @@ | ||
add_executable( | ||
unit | ||
unit.cpp | ||
${SIGFN_SOURCES}) | ||
# add_executable( | ||
# unit | ||
# unit.cpp | ||
# ${SIGFN_SOURCES}) | ||
|
||
target_include_directories(unit PRIVATE ${SIGFN_INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}/../src) | ||
# target_include_directories(unit PRIVATE ${SIGFN_INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}/../src) | ||
|
||
if(SIGFN_COVER) | ||
if(WIN32) | ||
message("skipping code coverage for windows") | ||
else() | ||
target_compile_options(unit PRIVATE -fprofile-arcs -ftest-coverage -g -O0) | ||
target_link_libraries(unit PRIVATE gcov "--coverage") | ||
add_custom_target( | ||
cover | ||
DEPENDS unit) | ||
add_custom_command( | ||
TARGET cover | ||
COMMAND gcovr -r ${CMAKE_CURRENT_SOURCE_DIR}/.. -e ${CMAKE_CURRENT_SOURCE_DIR}) | ||
endif() | ||
endif() | ||
# if(SIGFN_COVER) | ||
# if(WIN32) | ||
# message("skipping code coverage for windows") | ||
# else() | ||
# target_compile_options(unit PRIVATE -fprofile-arcs -ftest-coverage -g -O0) | ||
# target_link_libraries(unit PRIVATE gcov "--coverage") | ||
# add_custom_target( | ||
# cover | ||
# DEPENDS unit) | ||
# add_custom_command( | ||
# TARGET cover | ||
# COMMAND gcovr -r ${CMAKE_CURRENT_SOURCE_DIR}/.. -e ${CMAKE_CURRENT_SOURCE_DIR}) | ||
# endif() | ||
# endif() | ||
|
||
add_test(NAME sigfn_handle COMMAND unit sigfn_handle ) | ||
add_test(NAME sigfn_ignore COMMAND unit sigfn_ignore) | ||
add_test(NAME sigfn_reset COMMAND unit sigfn_reset) | ||
add_test(NAME sigfn_error COMMAND unit sigfn_error) | ||
add_test(NAME sigfn::handle COMMAND unit sigfn::handle) | ||
add_test(NAME sigfn::ignore COMMAND unit sigfn::ignore) | ||
add_test(NAME sigfn::reset COMMAND unit sigfn::reset) | ||
# add_test(NAME sigfn_handle COMMAND unit sigfn_handle ) | ||
# add_test(NAME sigfn_ignore COMMAND unit sigfn_ignore) | ||
# add_test(NAME sigfn_reset COMMAND unit sigfn_reset) | ||
# add_test(NAME sigfn_error COMMAND unit sigfn_error) | ||
# add_test(NAME sigfn::handle COMMAND unit sigfn::handle) | ||
# add_test(NAME sigfn::ignore COMMAND unit sigfn::ignore) | ||
# add_test(NAME sigfn::reset COMMAND unit sigfn::reset) | ||
|
||
add_library(threadpool_a STATIC threadpool.cpp) | ||
target_include_directories(threadpool_a PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) | ||
|
||
add_library(threadpool SHARED threadpool.cpp) | ||
target_include_directories(threadpool PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) | ||
|
||
add_library(threadpool INTERFACE) | ||
|
||
target_include_directories(threadpool INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) |
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,83 @@ | ||
#include <iostream> | ||
#include "threadpool.hpp" | ||
|
||
maxtek::threadpool::threadpool(size_t threads) | ||
{ | ||
if (threads == 0) | ||
{ | ||
throw std::runtime_error("failed to construct threadpool with zero threads"); | ||
} | ||
|
||
_active = true; | ||
|
||
_workers.reserve(threads); | ||
|
||
while (_workers.size() < _workers.capacity()) | ||
{ | ||
_workers.push_back(std::thread([&]() | ||
{ | ||
std::function<void()> task; | ||
while (pop_task(task)) | ||
{ | ||
task(); | ||
} })); | ||
} | ||
} | ||
|
||
maxtek::threadpool::~threadpool() | ||
{ | ||
if (_active) | ||
{ | ||
shutdown(); | ||
} | ||
} | ||
|
||
bool maxtek::threadpool::active() const | ||
{ | ||
return _active; | ||
} | ||
|
||
void maxtek::threadpool::shutdown() | ||
{ | ||
if (!_active) | ||
{ | ||
throw std::runtime_error("failed to shut down inactive threadpool"); | ||
} | ||
_active = false; | ||
_condition.notify_all(); | ||
for (std::thread &worker : _workers) | ||
{ | ||
worker.join(); | ||
} | ||
} | ||
|
||
void maxtek::threadpool::push_task(std::function<void()> &&task) | ||
{ | ||
std::unique_lock<std::mutex> lock(_mutex); | ||
if (!_active) | ||
{ | ||
throw std::runtime_error("failed to submit to inactive threadpool"); | ||
} | ||
_tasks.push(std::move(task)); | ||
lock.unlock(); | ||
_condition.notify_one(); | ||
} | ||
|
||
bool maxtek::threadpool::pop_task(std::function<void()> &task) | ||
{ | ||
std::unique_lock<std::mutex> lock(_mutex); | ||
bool result(false); | ||
_condition.wait( | ||
lock, | ||
[&]() | ||
{ | ||
return (!_active || !_tasks.empty()); | ||
}); | ||
if (_active) | ||
{ | ||
task = _tasks.front(); | ||
_tasks.pop(); | ||
result = true; | ||
} | ||
return result; | ||
} |
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,124 @@ | ||
/* | ||
** Copyright 2024 Maxtek Consulting | ||
** | ||
** Permission is hereby granted, free of charge, to any person obtaining a copy | ||
** of this software and associated documentation files (the "Software"), to deal | ||
** in the Software without restriction, including without limitation the rights | ||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
** copies of the Software, and to permit persons to whom the Software is | ||
** furnished to do so, subject to the following conditions: | ||
** | ||
** The above copyright notice and this permission notice shall be included in all | ||
** copies or substantial portions of the Software. | ||
** | ||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
** SOFTWARE. | ||
*/ | ||
|
||
#ifndef THREADPOOL_HPP | ||
#define THREADPOOL_HPP | ||
|
||
/** | ||
* @file threadpool.hpp | ||
* @brief Maxtek threadpool | ||
* @author Max Guerrero and John R. Patek Sr. | ||
*/ | ||
|
||
#include <algorithm> | ||
#include <functional> | ||
#include <future> | ||
#include <memory> | ||
#include <queue> | ||
#include <thread> | ||
#include <typeinfo> | ||
#include <vector> | ||
|
||
#ifdef _WIN32 | ||
#define DLL_EXPORT __declspec(dllexport) | ||
#else | ||
#define DLL_EXPORT | ||
#endif | ||
|
||
namespace maxtek | ||
{ | ||
/** | ||
* @brief threadpool | ||
* | ||
* @class allows tasks to be submitted and executed asynchronously across multiple threads. | ||
*/ | ||
class DLL_EXPORT threadpool | ||
{ | ||
public: | ||
|
||
/** | ||
* @brief constructs a new threadpool | ||
* | ||
* @param threads number of threads to use for constructing the threadpool | ||
* @exception std::runtime_error if threads is set to zero | ||
*/ | ||
threadpool(size_t threads = std::thread::hardware_concurrency()); | ||
|
||
/** | ||
* @brief destroys threadpool after calling shutdown if necessary | ||
*/ | ||
~threadpool(); | ||
|
||
/** | ||
* @brief submits a function with its arguments to the threadpool | ||
* @tparam F function signature | ||
* @tparam Args function argument types | ||
* @param function function signature | ||
* @param args arguments to pass to the function | ||
* @returns a future holding the asynchronous function result | ||
* @exception std::runtime_error if the thread pool has been shut down | ||
*/ | ||
template <class F, class... Args> | ||
std::future<std::result_of_t<F(Args...)>> submit(F &&function, Args &&...args) | ||
{ | ||
std::shared_ptr<std::packaged_task<std::result_of_t<F(Args...)>()>> packaged_task; | ||
std::function<void()> work; | ||
std::future<std::result_of_t<F(Args...)>> result; | ||
|
||
packaged_task = std::make_shared<std::packaged_task<std::result_of_t<F(Args...)>()>>(std::bind(std::forward<F>(function), std::forward<Args>(args)...)); | ||
result = packaged_task->get_future(); | ||
|
||
work = [packaged_task]() | ||
{ | ||
(*packaged_task)(); | ||
}; | ||
|
||
push_task(std::move(work)); | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* @brief check if the threadpool is active | ||
* @returns true if the threadpool is active, false if it has been shut down | ||
*/ | ||
bool active() const; | ||
|
||
/** | ||
* @brief shut down threadpool by joining threads and rejecting submissions | ||
* @exception std::runtime_error if the thread pool has already been shut down | ||
*/ | ||
void shutdown(); | ||
|
||
private: | ||
void push_task(std::function<void()> &&task); | ||
bool pop_task(std::function<void()> &task); | ||
|
||
size_t num_threads; | ||
bool _active; | ||
std::vector<std::thread> _workers; | ||
std::queue<std::function<void()>> _tasks; | ||
std::mutex _mutex; | ||
std::condition_variable _condition; | ||
}; | ||
} | ||
#endif |