pax_global_header00006660000000000000000000000064137564537750014540gustar00rootroot0000000000000052 comment=3f5aaacf1af7cb47cbc918812a7af42e290c7031 thread_pool-3.0.2/000077500000000000000000000000001375645377500140425ustar00rootroot00000000000000thread_pool-3.0.2/.gitignore000066400000000000000000000000371375645377500160320ustar00rootroot00000000000000# Compiled Object files build/ thread_pool-3.0.2/.gitmodules000066400000000000000000000000011375645377500162060ustar00rootroot00000000000000 thread_pool-3.0.2/.travis.yml000066400000000000000000000022661375645377500161610ustar00rootroot00000000000000dist: trusty language: cpp matrix: include: - name: "GCC 4.8 (Linux)" # GCC 4.8.5 & CMake 3.9.2 os: linux addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 - cmake env: - SET_COMPILER="export CC=gcc-4.8 && export CXX=g++-4.8" - name: "Clang 3.5 (Linux)" # Clang 3.5.0 & CMake 3.9.2 os: linux addons: apt: sources: - llvm-toolchain-trusty-3.5 packages: - clang-3.5 - cmake env: - SET_COMPILER="export CC=clang-3.5 && export CXX=clang++-3.5" - name: "Clang Xcode 9.0 (OSX)" # Clang 9.0.0 & CMake 3.9.2 os: osx osx_image: xcode9 before_install: - eval "${SET_COMPILER}" - git clone https://github.com/google/googletest && cd googletest && mkdir build && cd build && git checkout 703bd9c - cmake -DCMAKE_CXX_FLAGS="-std=c++11" .. && make && sudo make install - cd ../../ install: - mkdir build && cd build - cmake -Dthread_pool_build_tests=ON -DCMAKE_BUILD_TYPE=Release .. && make script: - ./bin/thread_pool_test notifications: email: on_failure: always thread_pool-3.0.2/CMakeLists.txt000066400000000000000000000022521375645377500166030ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.9) project(thread_pool VERSION 3.0.2 LANGUAGES CXX DESCRIPTION "ThreadPool is a c++ header only library modifying and extending https://github.com/progschj/ThreadPool.") 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) find_package(Threads REQUIRED) add_library(${PROJECT_NAME} INTERFACE) target_link_libraries(${PROJECT_NAME} INTERFACE Threads::Threads) target_include_directories(${PROJECT_NAME} INTERFACE $) option(thread_pool_build_tests "Build thread_pool unit tests" OFF) if (thread_pool_build_tests) find_package(GTest REQUIRED) add_executable(${PROJECT_NAME}_test test/semaphore_test.cpp test/thread_pool_test.cpp) target_link_libraries(${PROJECT_NAME}_test ${PROJECT_NAME} GTest::Main) endif () thread_pool-3.0.2/LICENSE000066400000000000000000000020551375645377500150510ustar00rootroot00000000000000MIT 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-3.0.2/README.md000066400000000000000000000037451375645377500153320ustar00rootroot00000000000000# 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 modifying and extending https://github.com/progschj/ThreadPool. ## Usage If you would like to add thread_pool to your project via CMake, add the following: ```cmake if (NOT TARGET thread_pool) add_subdirectory(/thread_pool EXCLUDE_FROM_ALL) endif () target_link_libraries( thread_pool) ``` If you are not using CMake, include the appropriate header file directly to your project and link with pthread. #### Dependencies - gcc 4.8+ or clang 3.5+ - (optional) cmake 3.9+ ## Examples ```cpp #include "thread_pool/thread_pool.hpp" int function1(const T& t, ...) { ... } int function2(...) { ... } ... auto lambda1 = [...] (...) -> void { ... }; 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(); } ``` ## Unit tests To build and run thread_pool unit tests run the following commands: ```bash git clone https://github.com/rvaser/thread_pool.git thread_pool cd thread_pool && mkdir build && cd build cmake -Dthread_pool_build_tests=ON -DCMAKE_BUILD_TYPE=Release .. && make ./bin/thread_pool_test ``` #### Dependencies - gtest ## 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-3.0.2/include/000077500000000000000000000000001375645377500154655ustar00rootroot00000000000000thread_pool-3.0.2/include/thread_pool/000077500000000000000000000000001375645377500177655ustar00rootroot00000000000000thread_pool-3.0.2/include/thread_pool/semaphore.hpp000066400000000000000000000016641375645377500224700ustar00rootroot00000000000000// Copyright (c) 2020 Robert Vaser #ifndef THREAD_POOL_SEMAPHORE_HPP_ #define THREAD_POOL_SEMAPHORE_HPP_ #include // NOLINT #include #include #include // NOLINT namespace thread_pool { class Semaphore { public: explicit Semaphore(std::uint32_t count) : count_(count) {} Semaphore(const Semaphore&) = delete; Semaphore& operator=(const Semaphore&) = delete; Semaphore(Semaphore&&) = delete; Semaphore& operator=(Semaphore&&) = delete; ~Semaphore() = default; void Wait() { std::unique_lock lock(mutex_); condition_.wait(lock, [&] () { return count_; }); --count_; } void Signal() { std::unique_lock lock(mutex_); ++count_; condition_.notify_one(); } private: std::uint32_t count_; std::mutex mutex_; std::condition_variable condition_; }; } // namespace thread_pool #endif // THREAD_POOL_SEMAPHORE_HPP_ thread_pool-3.0.2/include/thread_pool/thread_pool.hpp000066400000000000000000000054131375645377500230010ustar00rootroot00000000000000// Copyright (c) 2020 Robert Vaser #ifndef THREAD_POOL_THREAD_POOL_HPP_ #define THREAD_POOL_THREAD_POOL_HPP_ #include #include #include #include #include // NOLINT #include #include #include #include // NOLINT #include #include #include #include "thread_pool/semaphore.hpp" namespace thread_pool { class ThreadPool { public: ThreadPool(std::uint32_t num_threads = std::thread::hardware_concurrency() / 2) // NOLINT : threads_(), thread_ids_(), thread_semaphore_(0), queue_(), queue_semaphore_(1), terminate_(false) { num_threads = std::max(1U, num_threads); while (num_threads-- != 0) { threads_.emplace_back(ThreadPool::Task, this); thread_ids_.emplace(threads_.back().get_id(), threads_.size() - 1); } } ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; ThreadPool(ThreadPool&&) = delete; ThreadPool& operator=(ThreadPool&&) = delete; ~ThreadPool() { terminate_ = true; for (std::uint32_t i = 0; i < threads_.size(); ++i) { thread_semaphore_.Signal(); } for (auto& it : threads_) { it.join(); } } std::uint32_t num_threads() const { return threads_.size(); } const std::unordered_map& thread_ids() const { return thread_ids_; } 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)(); }; queue_semaphore_.Wait(); queue_.emplace(task_wrapper); queue_semaphore_.Signal(); thread_semaphore_.Signal(); return task_result; } private: static void Task(ThreadPool* thread_pool) { while (true) { thread_pool->thread_semaphore_.Wait(); if (thread_pool->terminate_) { break; } thread_pool->queue_semaphore_.Wait(); auto task = std::move(thread_pool->queue_.front()); thread_pool->queue_.pop(); thread_pool->queue_semaphore_.Signal(); if (thread_pool->terminate_) { break; } task(); } } std::vector threads_; std::unordered_map thread_ids_; Semaphore thread_semaphore_; std::queue> queue_; Semaphore queue_semaphore_; std::atomic terminate_; }; } // namespace thread_pool #endif // THREAD_POOL_THREAD_POOL_HPP_ thread_pool-3.0.2/test/000077500000000000000000000000001375645377500150215ustar00rootroot00000000000000thread_pool-3.0.2/test/semaphore_test.cpp000066400000000000000000000010741375645377500205510ustar00rootroot00000000000000// Copyright (c) 2020 Robert Vaser #include "thread_pool/semaphore.hpp" #include // NOLINT #include "gtest/gtest.h" namespace thread_pool { namespace test { TEST(ThreadPoolSemaphoreTest, Barrier) { Semaphore s{0}, b{0}; auto check = [&] () -> void { s.Signal(); b.Wait(); }; std::thread t1{check}; std::thread t2{check}; std::thread t3{check}; s.Wait(); s.Wait(); s.Wait(); // Release barrier b.Signal(); b.Signal(); b.Signal(); t1.join(); t2.join(); t3.join(); } } // namespace test } // namespace thread_pool thread_pool-3.0.2/test/thread_pool_test.cpp000066400000000000000000000030101375645377500210560ustar00rootroot00000000000000// Copyright (c) 2020 Robert Vaser #include "thread_pool/thread_pool.hpp" #include #include #include #include "gtest/gtest.h" namespace thread_pool { namespace test { TEST(ThreadPoolThreadPoolTest, Submit) { std::function fibonacci = [&fibonacci] (std::uint32_t i) -> std::uint32_t { if (i == 1 || i == 2) { return 1; } return fibonacci(i - 1) + fibonacci(i - 2); }; ThreadPool tp{}; std::vector> f; for (std::uint32_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_ids().size()); Semaphore s{0}, b{0}; auto check = [&] () -> std::uint32_t { EXPECT_EQ(1, tp.thread_ids().count(std::this_thread::get_id())); s.Signal(); b.Wait(); return tp.thread_ids().at(std::this_thread::get_id()); }; std::vector> f; for (std::uint32_t i = 0; i < tp.num_threads(); ++i) { f.emplace_back(tp.Submit(check)); } for (std::uint32_t i = 0; i < tp.num_threads(); ++i) { s.Wait(); } for (std::uint32_t i = 0; i < tp.num_threads(); ++i) { b.Signal(); } std::unordered_set ts; for (auto& it : f) { ts.emplace(it.get()); } EXPECT_EQ(tp.num_threads(), ts.size()); } } // namespace test } // namespace thread_pool