pax_global_header00006660000000000000000000000064140635222460014516gustar00rootroot0000000000000052 comment=6af80b2862dc95d596a645af8d0aedfa2259a62e thread_pool-4.0.0/000077500000000000000000000000001406352224600140175ustar00rootroot00000000000000thread_pool-4.0.0/.gitignore000066400000000000000000000000371406352224600160070ustar00rootroot00000000000000# Compiled Object files build/ thread_pool-4.0.0/.gitmodules000066400000000000000000000000011406352224600161630ustar00rootroot00000000000000 thread_pool-4.0.0/.travis.yml000066400000000000000000000016051406352224600161320ustar00rootroot00000000000000language: cpp matrix: include: - name: "GCC 4.8 (Linux)" # GCC 4.8.5 & CMake 3.12.4 os: linux dist: xenial addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 env: - SET_COMPILER="export CC=gcc-4.8 && export CXX=g++-4.8" - name: "Clang 3.5 (Linux)" # Clang 3.5.2 & CMake 3.12.4 os: linux dist: xenial addons: apt: packages: - clang-3.5 env: - SET_COMPILER="export CC=clang-3.5 && export CXX=clang++-3.5" - name: "Clang Xcode 9.4 (OSX)" # Clang 9.4.1 & CMake 3.15.5 os: osx osx_image: xcode9.4 before_install: - eval "${SET_COMPILER}" install: - mkdir build && cd build - cmake -DCMAKE_BUILD_TYPE=Release .. && make script: - ./bin/thread_pool_test notifications: email: on_failure: always thread_pool-4.0.0/CMakeLists.txt000066400000000000000000000055731406352224600165710ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.11) project(thread_pool VERSION 4.0.0 LANGUAGES CXX DESCRIPTION "ThreadPool is a c++ header only library combining https://github.com/progschj/ThreadPool and task stealing by Sean Parent.") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(THREADS_PREFER_PTHREAD_FLAG ON) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) set(thread_pool_main_project ON) endif () option(thread_pool_install "Generate install target" ${thread_pool_main_project}) option(thread_pool_build_tests "Build unit tests" ${thread_pool_main_project}) find_package(Threads REQUIRED) if (thread_pool_build_tests) find_package(GTest 1.10.0 QUIET) if (NOT GTest_FOUND) include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest GIT_TAG release-1.10.0) FetchContent_GetProperties(googletest) if (NOT googletest_POPULATED) FetchContent_Populate(googletest) add_subdirectory( ${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) add_library(GTest::Main ALIAS gtest_main) endif () endif () endif () add_library(thread_pool INTERFACE) add_library(${PROJECT_NAME}::thread_pool ALIAS thread_pool) target_include_directories(thread_pool INTERFACE $ $) target_link_libraries(thread_pool INTERFACE Threads::Threads) if (thread_pool_install) include(GNUInstallDirs) include(CMakePackageConfigHelpers) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake COMPATIBILITY SameMajorVersion) install( TARGETS thread_pool EXPORT ${PROJECT_NAME}Targets) install( DIRECTORY include/thread_pool DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install( EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) endif () if (thread_pool_build_tests) add_executable(thread_pool_test test/thread_pool_test.cpp) target_link_libraries(thread_pool_test thread_pool GTest::Main) endif () thread_pool-4.0.0/Config.cmake.in000066400000000000000000000002711406352224600166330ustar00rootroot00000000000000@PACKAGE_INIT@ include(CMakeFindDependencyMacro) find_dependency(Threads) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") thread_pool-4.0.0/LICENSE000066400000000000000000000020551406352224600150260ustar00rootroot00000000000000MIT License Copyright (c) 2017 Robert Vaser 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. thread_pool-4.0.0/README.md000066400000000000000000000045311406352224600153010ustar00rootroot00000000000000# Thread pool [![Latest GitHub release](https://img.shields.io/github/release/rvaser/thread_pool.svg)](https://github.com/rvaser/thread_pool/releases/latest) [![Build status for c++/clang++](https://travis-ci.com/rvaser/thread_pool.svg?branch=master)](https://travis-ci.com/rvaser/thread_pool) ThreadPool is a c++ header only library combining https://github.com/progschj/ThreadPool and task stealing by Sean Parent. ## Usage To build thread_pool run the following commands: ```bash git clone https://github.com/rvaser/thread_pool && cd thread_pool && mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. && make ``` which will create install targets and unit tests. Running `make install` will create a package on your system that can be searched and linked with: ```cmake find_package(thread_pool) target_link_libraries( thread_pool:thread_pool) ``` On the other hand, you can include thread_pool as a submodule and add it to your project with the following: ```cmake if (NOT TARGET thread_pool) add_subdirectory(/thread_pool EXCLUDE_FROM_ALL) endif () target_link_libraries( thread_pool::thread_pool) ``` If you are not using CMake, include the appropriate header file directly to your project and link with pthread. #### Build options - `thread_pool_install`: generate install target - `thread_pool_build_tests`: build unit tests #### Dependencies - gcc 4.8+ | clang 3.5+ - pthread - (optional) cmake 3.11+ ###### Hidden - (thread_pool_test) google/googletest 1.10.0 ## Examples ```cpp #include "thread_pool/thread_pool.hpp" int function1(const T& t, ...) { ... } int function2(...) { ... } ... auto lambda1 = [...] (...) -> void { ... }; thread_pool::ThreadPool thread_pool{}; std::vector> futures; for (...) { // be sure to used std::ref() or std::cref() for references futures.emplace_back(thread_pool.Submit(function1, std::cref(t), ...)); futures.emplace_back(thread_pool.Submit(function2, ...)); } for (auto& it : futures) { ... = it.get(); } std::vector> void_futures; for (...) { void_futures.emplace_back(thread_pool.Submit(lambda1, ...)); } for (const auto& it : void_futures) { it.wait(); } ``` ## Acknowledgement This work has been supported in part by the Croatian Science Foundation under the project Single genome and metagenome assembly (IP-2018-01-5886). thread_pool-4.0.0/include/000077500000000000000000000000001406352224600154425ustar00rootroot00000000000000thread_pool-4.0.0/include/thread_pool/000077500000000000000000000000001406352224600177425ustar00rootroot00000000000000thread_pool-4.0.0/include/thread_pool/thread_pool.hpp000066400000000000000000000100501406352224600227470ustar00rootroot00000000000000// Copyright (c) 2020 Robert Vaser // Combination of ThreadPool implementation by progschj and // task stealing by Sean Parent #ifndef THREAD_POOL_THREAD_POOL_HPP_ #define THREAD_POOL_THREAD_POOL_HPP_ #include #include #include #include // NOLINT #include #include #include // NOLINT #include #include #include namespace thread_pool { class ThreadPool { public: explicit ThreadPool( std::size_t num_threads = std::thread::hardware_concurrency()) : threads_(), thread_map_(), queues_(std::max(1UL, num_threads)), task_id_(0) { for (std::size_t i = 0; i != queues_.size(); ++i) { threads_.emplace_back([this, i] () -> void { Task(i); }); thread_map_.emplace(threads_.back().get_id(), i); } } ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; ThreadPool(ThreadPool&&) = delete; ThreadPool& operator=(ThreadPool&&) = delete; ~ThreadPool() { for (auto& it : queues_) { it.Done(); } for (auto& it : threads_) { it.join(); } } std::size_t num_threads() const { return threads_.size(); } const std::unordered_map& thread_map() const { return thread_map_; } template auto Submit(T&& routine, Ts&&... params) -> std::future::type> { auto task = std::make_shared::type()>>( // NOLINT std::bind(std::forward(routine), std::forward(params)...)); auto task_result = task->get_future(); auto task_wrapper = [task] () { (*task)(); }; auto task_id = task_id_++; bool is_submitted = false; for (std::size_t i = 0; i != queues_.size() * 42; ++i) { if (queues_[(task_id + i) % queues_.size()].TryPush(task_wrapper)) { is_submitted = true; break; } } if (!is_submitted) { queues_[task_id % queues_.size()].Push(task_wrapper); } return task_result; } private: void Task(std::size_t thread_id) { while (true) { std::function task; for (std::size_t i = 0; i != queues_.size(); ++i) { if (queues_[(thread_id + i) % queues_.size()].TryPop(&task)) { break; } } if (!task && !queues_[thread_id].Pop(&task)) { break; } task(); } } struct TaskQueue { public: template void Push(F&& f) { { std::unique_lock lock(mutex); queue.emplace(std::forward(f)); } is_ready.notify_one(); } bool Pop(std::function* f) { std::unique_lock lock(mutex); while (queue.empty() && !is_done) { is_ready.wait(lock); } if (queue.empty()) { return false; } *f = std::move(queue.front()); queue.pop(); return true; } template bool TryPush(F&& f) { { std::unique_lock lock(mutex, std::try_to_lock); if (!lock) { return false; } queue.emplace(std::forward(f)); } is_ready.notify_one(); return true; } bool TryPop(std::function* f) { std::unique_lock lock(mutex, std::try_to_lock); if (!lock || queue.empty()) { return false; } *f = std::move(queue.front()); queue.pop(); return true; } void Done() { { std::unique_lock lock(mutex); is_done = true; } is_ready.notify_all(); } std::queue> queue; std::mutex mutex; std::condition_variable is_ready; bool is_done = false; }; std::vector threads_; std::unordered_map thread_map_; std::vector queues_; std::atomic task_id_; }; } // namespace thread_pool #endif // THREAD_POOL_THREAD_POOL_HPP_ thread_pool-4.0.0/test/000077500000000000000000000000001406352224600147765ustar00rootroot00000000000000thread_pool-4.0.0/test/thread_pool_test.cpp000066400000000000000000000021261406352224600210420ustar00rootroot00000000000000// Copyright (c) 2020 Robert Vaser #include "thread_pool/thread_pool.hpp" #include "gtest/gtest.h" namespace thread_pool { namespace test { TEST(ThreadPoolThreadPoolTest, Submit) { std::function fibonacci = [&fibonacci] (std::size_t i) -> std::size_t { if (i == 1 || i == 2) { return 1; } return fibonacci(i - 1) + fibonacci(i - 2); }; ThreadPool tp{}; std::vector> f; for (std::size_t i = 0; i < tp.num_threads(); ++i) { f.emplace_back(tp.Submit(fibonacci, 42)); } for (auto& it : f) { EXPECT_EQ(267914296, it.get()); } } TEST(ThreadPoolThreadPoolTest, ThreadIds) { ThreadPool tp{}; EXPECT_EQ(tp.num_threads(), tp.thread_map().size()); auto thread_id = [&] () -> std::size_t { return tp.thread_map().count(std::this_thread::get_id()); }; std::vector> f; for (std::size_t i = 0; i < tp.num_threads() * 42; ++i) { f.emplace_back(tp.Submit(thread_id)); } for (auto& it : f) { EXPECT_EQ(1, it.get()); } } } // namespace test } // namespace thread_pool