[med-svn] [Git][med-team/libthread-pool][master] 14 commits: debian/watch: Uniquely rename the archives download from GitHub.
Michael R. Crusoe
gitlab at salsa.debian.org
Tue Jan 19 07:51:03 GMT 2021
Michael R. Crusoe pushed to branch master at Debian Med / libthread-pool
Commits:
f348a87d by Michael R. Crusoe at 2021-01-18T16:52:42+01:00
debian/watch: Uniquely rename the archives download from GitHub.
- - - - -
5af18253 by Michael R. Crusoe at 2021-01-18T16:52:42+01:00
routine-update: Standards-Version: 4.5.1
- - - - -
90f33712 by Michael R. Crusoe at 2021-01-18T16:52:42+01:00
routine-update: debhelper-compat 13
- - - - -
4d6784bb by Michael R. Crusoe at 2021-01-18T16:54:39+01:00
routine-update: New upstream version
- - - - -
1d3149f9 by Michael R. Crusoe at 2021-01-18T16:54:41+01:00
New upstream version 3.0.2
- - - - -
e94e96a9 by Michael R. Crusoe at 2021-01-18T16:54:42+01:00
Update upstream source from tag 'upstream/3.0.2'
Update to upstream version '3.0.2'
with Debian dir 7c88db588f2a0bb5948722275ca00c1c086e48a3
- - - - -
e80d9611 by Michael R. Crusoe at 2021-01-18T16:57:59+01:00
Library is header-only now.
- - - - -
ede8f169 by Michael R. Crusoe at 2021-01-18T16:58:35+01:00
routine-update: Add salsa-ci file
- - - - -
33e2fb87 by Michael R. Crusoe at 2021-01-18T16:58:36+01:00
routine-update: Rules-Requires-Root: no
- - - - -
c34c3859 by Michael R. Crusoe at 2021-01-18T16:58:37+01:00
Set upstream metadata fields: Bug-Database, Bug-Submit, Repository-Browse..
Changes-By: lintian-brush
Fixes: lintian: upstream-metadata-missing-bug-tracking
See-also: https://lintian.debian.org/tags/upstream-metadata-missing-bug-tracking.html
Fixes: lintian: upstream-metadata-missing-repository
See-also: https://lintian.debian.org/tags/upstream-metadata-missing-repository.html
- - - - -
5753e9a4 by Michael R. Crusoe at 2021-01-19T08:39:03+01:00
debian/rules: no more vendor directory
- - - - -
95b26361 by Michael R. Crusoe at 2021-01-19T08:39:03+01:00
build-dep on libgtest-dev so that cmake can find it
- - - - -
188cc9c8 by Michael R. Crusoe at 2021-01-19T08:50:09+01:00
more header-only changes
- - - - -
797a99f2 by Michael R. Crusoe at 2021-01-19T08:50:09+01:00
routine-update: Ready to upload to unstable
- - - - -
20 changed files:
- .gitmodules
- .travis.yml
- CMakeLists.txt
- README.md
- debian/changelog
- debian/control
- + debian/install
- − debian/patches/series
- − debian/patches/shared_and_static.patch
- − debian/patches/soversion.patch
- debian/rules
- + debian/salsa-ci.yml
- debian/tests/CMakeLists.txt
- debian/upstream/metadata
- debian/watch
- + include/thread_pool/semaphore.hpp
- include/thread_pool/thread_pool.hpp
- − src/thread_pool.cpp
- + test/semaphore_test.cpp
- test/thread_pool_test.cpp
Changes:
=====================================
.gitmodules
=====================================
@@ -1,3 +1 @@
-[submodule "vendor/googletest"]
- path = vendor/googletest
- url = https://github.com/google/googletest
+
=====================================
.travis.yml
=====================================
@@ -2,42 +2,49 @@ dist: trusty
language: cpp
-compiler:
- - clang
- - gcc
+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:
- # cmake 3.2
- - sudo add-apt-repository ppa:george-edison55/cmake-3.x -y
-
- # g++4.8.1
- - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
-
- # clang 3.4
- - if [ "$CXX" == "clang++" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm; fi
-
- - sudo apt-get update -qq
+ - 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:
- # cmake 3.2
- - sudo apt-get install cmake cmake-data
-
- # g++4.8.1
- - sudo apt-get install -qq g++-4.8
- - if [ "$CXX" == "g++" ]; then export CXX="g++-4.8"; fi
-
- # clang 3.4
- - if [ "$CXX" == "clang++" ]; then sudo apt-get install --allow-unauthenticated -qq clang-3.4; fi
- - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.4"; fi
+ - mkdir build && cd build
+ - cmake -Dthread_pool_build_tests=ON -DCMAKE_BUILD_TYPE=Release .. && make
script:
- - mkdir build
- - cd build
- - cmake -DCMAKE_BUILD_TYPE=Release -Dthread_pool_build_tests=ON ..
- - make
- - ./bin/thread_pool_test
+ - ./bin/thread_pool_test
notifications:
- email:
- on_success: change
- on_failure: always
+ email:
+ on_failure: always
=====================================
CMakeLists.txt
=====================================
@@ -1,11 +1,8 @@
-cmake_minimum_required(VERSION 3.2)
-project(thread_pool)
+cmake_minimum_required(VERSION 3.9)
-include(GNUInstallDirs)
-
-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)
+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)
@@ -13,28 +10,25 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(THREADS_PREFER_PTHREAD_FLAG ON)
-find_package(Threads REQUIRED)
-
-option(thread_pool_build_tests "Build thread_pool unit tests" OFF)
-
-add_library(thread_pool STATIC
- src/thread_pool.cpp)
-
-target_link_libraries(thread_pool Threads::Threads)
+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)
-target_include_directories(thread_pool PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
- $<INSTALL_INTERFACE:include>)
+find_package(Threads REQUIRED)
+add_library(${PROJECT_NAME} INTERFACE)
+target_link_libraries(${PROJECT_NAME} INTERFACE
+ Threads::Threads)
-install(TARGETS thread_pool DESTINATION ${CMAKE_INSTALL_LIBDIR})
-install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/thread_pool DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+target_include_directories(${PROJECT_NAME} INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+option(thread_pool_build_tests "Build thread_pool unit tests" OFF)
if (thread_pool_build_tests)
- add_executable(thread_pool_test test/thread_pool_test.cpp)
-
- if (NOT TARGET gtest_main)
- add_subdirectory(vendor/googletest/googletest EXCLUDE_FROM_ALL)
- endif()
-
- target_link_libraries(thread_pool_test thread_pool gtest_main)
-endif()
+ 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 ()
=====================================
README.md
=====================================
@@ -1,79 +1,78 @@
# Thread pool
[![Latest GitHub release](https://img.shields.io/github/release/rvaser/thread_pool.svg)](https://github.com/rvaser/thread_pool/releases/latest)
-![image](https://travis-ci.org/rvaser/thread_pool.svg?branch=master)
+[![Build status for c++/clang++](https://travis-ci.com/rvaser/thread_pool.svg?branch=master)](https://travis-ci.com/rvaser/thread_pool)
-A c++ thread pool implementation inspired by https://github.com/progschj/ThreadPool.
+ThreadPool is a c++ header only library modifying and extending https://github.com/progschj/ThreadPool.
-## Dependencies
-
-### Linux
-
-Application uses following software:
-
-1. gcc 4.8+ or clang 3.4+
-2. cmake 3.2+
-
-## Instalation
-
-By running the following commands:
+## Usage
-```bash
-git clone https://github.com/rvaser/thread_pool.git thread_pool
-cd thread_pool
-mkdir build
-cd build
-cmake -DCMAKE_BUILD_TYPE=Release ..
-make
+If you would like to add thread_pool to your project via CMake, add the following:
+```cmake
+if (NOT TARGET thread_pool)
+ add_subdirectory(<path_to_submodules>/thread_pool EXCLUDE_FROM_ALL)
+endif ()
+target_link_libraries(<your_exe> thread_pool)
```
-a library named `libthread_pool.a` will appear in `build/lib` directory. Optionally, you can run `sudo make install` to install thread_pool library to your machine.
-
-Alternatively, add the project to your `CMakeLists.txt` file with `add_subdirectory(vendor/thread_pool EXCLUDE_FROM_ALL)` and `target_link_libraries(your_exe thread_pool)` commands.
+If you are not using CMake, include the appropriate header file directly to your project and link with pthread.
-To build unit tests run `git submodule update --init` and add `-Dthread_pool_build_tests=ON` while running `cmake`. After installation, an executable named `thread_pool_test` will be created in `build/bin`.
+#### Dependencies
-## Usage
+- gcc 4.8+ or clang 3.5+
+- (optional) cmake 3.9+
-For details on how to use the thread pool, please look at the example bellow:
+## Examples
```cpp
-// define some functions you want to execute in parallel
-int function1(std::vector<int>& data, int index, ...) {
- ...
+#include "thread_pool/thread_pool.hpp"
+
+int function1(const T& t, ...) {
+ ...
}
-int function2(float a, float b) {
- ...
+int function2(...) {
+ ...
}
-void function3(void) {
- ...
+...
+auto lambda1 = [...] (...) -> void {
+ ...
+};
+
+ThreadPool thread_pool{};
+
+std::vector<std::future<int>> 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, ...));
}
-
-// create thread pool
-std::shared_ptr<thread_pool::ThreadPool> thread_pool =
- thread_pool::createThreadPool(); // or pass number of threads you desire
-// or std::unique_ptr<thread_pool::ThreadPool> ...
-
-// create storage for return values of function1 and function2
-std::vector<std::future<int>> thread_futures;
-for (std::uint32_t i = 0; i < num_tasks; ++i) {
- // be sure to use std::ref() when passing references!
- thread_futures.emplace_back(thread_pool->submit(function1, std::ref(data), index, ...));
- thread_futures.emplace_back(thread_pool->submit(function2, a, b));
+for (auto& it : futures) {
+ ... = it.get();
}
-// wait for threads to finish
-for (auto& it: thread_futures) {
- it.wait();
- // get return value with it.get();
+std::vector<std::future<void>> void_futures;
+for (...) {
+ void_futures.emplace_back(thread_pool.Submit(lambda1, ...));
}
-
-// new set of tasks running function3
-std::vector<std::future<void>> thread_futures2;
-for (std::uint32_t i = 0; i < num_tasks2; ++i) {
- thread_futures2.emplace_back(thread_pool->submit(function3));
-}
-for (auto& it2: thread_futures2) {
- it.wait();
+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)..
=====================================
debian/changelog
=====================================
@@ -1,3 +1,18 @@
+libthread-pool (3.0.2-1) unstable; urgency=medium
+
+ * Team upload.
+ * debian/watch: Uniquely rename the archives download from GitHub.
+ * Standards-Version: 4.5.1 (routine-update)
+ * debhelper-compat 13 (routine-update)
+ * Library is header-only now.
+ * Add salsa-ci file (routine-update)
+ * Rules-Requires-Root: no (routine-update)
+ * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository-Browse.
+ * debian/rules: no more vendor directory
+ * build-dep on libgtest-dev so that cmake can find it
+
+ -- Michael R. Crusoe <crusoe at debian.org> Mon, 18 Jan 2021 16:58:37 +0100
+
libthread-pool (2.0.2-1) unstable; urgency=medium
* Team upload.
=====================================
debian/control
=====================================
@@ -3,41 +3,24 @@ Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.
Uploaders: Andreas Tille <tille at debian.org>
Section: science
Priority: optional
-Build-Depends: debhelper-compat (= 12),
+Build-Depends: debhelper-compat (= 13),
cmake,
d-shlibs,
rename,
- googletest
-Standards-Version: 4.5.0
+ libgtest-dev
+Standards-Version: 4.5.1
Vcs-Browser: https://salsa.debian.org/med-team/libthread-pool
Vcs-Git: https://salsa.debian.org/med-team/libthread-pool.git
Homepage: https://github.com/rvaser/thread_pool
-
-Package: libthread-pool0
-Architecture: any
-Section: libs
-Depends: ${shlibs:Depends},
- ${misc:Depends}
-Description: C++ thread pool library
- A thread pool is a software design pattern for achieving concurrency of
- execution in a computer program. Often also called a replicated workers
- or worker-crew model,[1] a thread pool maintains multiple threads
- waiting for tasks to be allocated for concurrent execution by the
- supervising program.
- .
- This package contains a shared library with a thread pool
- implementation.
+Rules-Requires-Root: no
Package: libthread-pool-dev
-Architecture: any
+Architecture: all
Section: libdevel
-Depends: ${misc:Depends},
- libthread-pool0 (= ${binary:Version})
-Description: C++ thread pool library (devel)
+Depends: ${misc:Depends}
+Description: C++ header-only thread pool library (devel)
A thread pool is a software design pattern for achieving concurrency of
execution in a computer program. Often also called a replicated workers
or worker-crew model,[1] a thread pool maintains multiple threads
waiting for tasks to be allocated for concurrent execution by the
supervising program.
- .
- This package contains the static library and the header files.
=====================================
debian/install
=====================================
@@ -0,0 +1 @@
+include/thread_pool /usr/include/
=====================================
debian/patches/series deleted
=====================================
@@ -1,2 +0,0 @@
-shared_and_static.patch
-soversion.patch
=====================================
debian/patches/shared_and_static.patch deleted
=====================================
@@ -1,31 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-Last-Update: Fri, 08 Jun 2018 13:20:51 +0200
-Description: Build shared and static lib
-
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -17,7 +17,10 @@ find_package(Threads REQUIRED)
-
- option(thread_pool_build_tests "Build thread_pool unit tests" OFF)
-
--add_library(thread_pool STATIC
-+add_library(thread_pool SHARED
-+ src/thread_pool.cpp)
-+
-+add_library(thread_pool_static STATIC
- src/thread_pool.cpp)
-
- target_link_libraries(thread_pool Threads::Threads)
-@@ -26,7 +29,12 @@ target_include_directories(thread_pool P
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
- $<INSTALL_INTERFACE:include>)
-
-+target_include_directories(thread_pool_static PUBLIC
-+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
-+ $<INSTALL_INTERFACE:include>)
-+
- install(TARGETS thread_pool DESTINATION ${CMAKE_INSTALL_LIBDIR})
-+install(TARGETS thread_pool_static DESTINATION lib)
- install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/thread_pool DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
-
- if (thread_pool_build_tests)
=====================================
debian/patches/soversion.patch deleted
=====================================
@@ -1,25 +0,0 @@
-Author: Andreas Tille <tille at debian.org>
-Last-Update: Fri, 08 Jun 2018 13:20:51 +0200
-Description: Add soversion
-
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -1,5 +1,5 @@
- cmake_minimum_required(VERSION 3.2)
--project(thread_pool)
-+project(thread_pool LANGUAGES CXX VERSION 1.0.0)
-
- include(GNUInstallDirs)
-
-@@ -25,6 +25,11 @@ add_library(thread_pool_static STATIC
-
- target_link_libraries(thread_pool Threads::Threads)
-
-+set_target_properties(thread_pool
-+ PROPERTIES
-+ VERSION ${thread_pool_VERSION}
-+ SOVERSION 0)
-+
- target_include_directories(thread_pool PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
- $<INSTALL_INTERFACE:include>)
=====================================
debian/rules
=====================================
@@ -9,22 +9,9 @@ export DEB_LDFLAGS_MAINT_APPEND+=-pthread
dh $@
override_dh_auto_configure:
- rm -Rf vendor/*
- ln -s /usr/src/googletest ./vendor/
dh_auto_configure -- -Dthread_pool_build_tests=ON
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
./obj-*/bin/thread_pool_test
endif
-
-override_dh_install:
- dh_install
- file-rename 's/_static\.a/.a/' `find debian -name "lib*_static.a"`
- mv debian/tmp/usr/lib/*.a debian/tmp/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH` # this somehow inserts i686-linux-gnu which is wrong: $(DEB_HOST_MULTIARCH)
- d-shlibmove --commit \
- --multiarch \
- --devunversioned \
- --exclude-la \
- --movedev debian/tmp/usr/include/* usr/include \
- debian/tmp/usr/lib/*/*.so
=====================================
debian/salsa-ci.yml
=====================================
@@ -0,0 +1,4 @@
+---
+include:
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
=====================================
debian/tests/CMakeLists.txt
=====================================
@@ -7,4 +7,4 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(thread_pool_test thread_pool_test.cpp)
add_subdirectory(/usr/src/googletest .. EXCLUDE_FROM_ALL)
-target_link_libraries(thread_pool_test thread_pool gtest_main)
+target_link_libraries(thread_pool_test gtest_main)
=====================================
debian/upstream/metadata
=====================================
@@ -1 +1,4 @@
+Bug-Database: https://github.com/rvaser/thread_pool/issues
+Bug-Submit: https://github.com/rvaser/thread_pool/issues/new
Repository: https://github.com/rvaser/thread_pool.git
+Repository-Browse: https://github.com/rvaser/thread_pool
=====================================
debian/watch
=====================================
@@ -1,3 +1,4 @@
version=4
-https://github.com/rvaser/thread_pool/releases .*/archive/@ANY_VERSION@@ARCHIVE_EXT@
+opts="filenamemangle=s%(?:.*?)?(\d[\d.]*)\.tar\.gz%@PACKAGE at -$1.tar.gz%" \
+ https://github.com/rvaser/thread_pool/releases .*/@ANY_VERSION@\.tar\.gz
=====================================
include/thread_pool/semaphore.hpp
=====================================
@@ -0,0 +1,46 @@
+// Copyright (c) 2020 Robert Vaser
+
+#ifndef THREAD_POOL_SEMAPHORE_HPP_
+#define THREAD_POOL_SEMAPHORE_HPP_
+
+#include <condition_variable> // NOLINT
+#include <cstdint>
+#include <memory>
+#include <mutex> // 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<std::mutex> lock(mutex_);
+ condition_.wait(lock, [&] () { return count_; });
+ --count_;
+ }
+
+ void Signal() {
+ std::unique_lock<std::mutex> 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_
=====================================
include/thread_pool/thread_pool.hpp
=====================================
@@ -1,107 +1,113 @@
-/*!
- * @file thread_pool.hpp
- *
- * @brief ThreadPool class header file
- */
+// Copyright (c) 2020 Robert Vaser
-#pragma once
+#ifndef THREAD_POOL_THREAD_POOL_HPP_
+#define THREAD_POOL_THREAD_POOL_HPP_
+#include <algorithm>
+#include <atomic>
#include <cstdint>
+#include <functional>
+#include <future> // NOLINT
#include <memory>
-#include <vector>
-#include <string>
#include <queue>
-#include <mutex>
-#include <thread>
-#include <future>
-#include <atomic>
-#include <functional>
-#include <condition_variable>
-
-namespace thread_pool {
-
-static const std::string version = "v2.0.2";
-
-class Semaphore;
-std::unique_ptr<Semaphore> createSemaphore(std::uint32_t value);
+#include <string>
+#include <thread> // NOLINT
+#include <unordered_map>
+#include <utility>
+#include <vector>
-class ThreadPool;
-std::unique_ptr<ThreadPool> createThreadPool(std::uint32_t num_threads =
- std::thread::hardware_concurrency() / 2);
+#include "thread_pool/semaphore.hpp"
-class Semaphore {
-public:
- ~Semaphore() = default;
+namespace thread_pool {
- std::uint32_t value() const {
- return value_;
+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);
}
+ }
- void wait();
- void post();
-
- friend std::unique_ptr<Semaphore> createSemaphore(std::uint32_t value);
-private:
- Semaphore(std::uint32_t value);
- Semaphore(const Semaphore&) = delete;
- const Semaphore& operator=(const Semaphore&) = delete;
-
- std::mutex mutex_;
- std::condition_variable condition_;
- std::uint32_t value_;
-};
+ ThreadPool(const ThreadPool&) = delete;
+ ThreadPool& operator=(const ThreadPool&) = delete;
-class ThreadPool {
-public:
- ~ThreadPool();
+ ThreadPool(ThreadPool&&) = delete;
+ ThreadPool& operator=(ThreadPool&&) = delete;
- std::uint32_t num_threads() const {
- return threads_.size();
+ ~ThreadPool() {
+ terminate_ = true;
+ for (std::uint32_t i = 0; i < threads_.size(); ++i) {
+ thread_semaphore_.Signal();
}
-
- const std::vector<std::thread::id>& thread_identifiers() const {
- return thread_identifiers_;
+ for (auto& it : threads_) {
+ it.join();
}
-
- template<typename T, typename... Ts>
- auto submit(T&& routine, Ts&&... params)
- -> std::future<typename std::result_of<T(Ts...)>::type> {
-
- auto task = std::make_shared<std::packaged_task<typename std::result_of<T(Ts...)>::type()>>(
- std::bind(std::forward<T>(routine), std::forward<Ts>(params)...)
- );
- auto task_result = task->get_future();
- auto task_wrapper = [task]() {
- (*task)();
- };
-
- queue_sem_->wait();
-
- task_queue_.emplace(task_wrapper);
-
- queue_sem_->post();
- active_sem_->post();
-
- return task_result;
+ }
+
+ std::uint32_t num_threads() const {
+ return threads_.size();
+ }
+
+ const std::unordered_map<std::thread::id, std::uint32_t>& thread_ids() const {
+ return thread_ids_;
+ }
+
+ template<typename T, typename... Ts>
+ auto Submit(T&& routine, Ts&&... params)
+ -> std::future<typename std::result_of<T(Ts...)>::type> {
+ auto task = std::make_shared<std::packaged_task<typename std::result_of<T(Ts...)>::type()>>( // NOLINT
+ std::bind(std::forward<T>(routine), std::forward<Ts>(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();
}
-
- friend std::unique_ptr<ThreadPool> createThreadPool(std::uint32_t num_threads);
-private:
- ThreadPool(std::uint32_t num_threads);
- ThreadPool(const ThreadPool&) = delete;
- const ThreadPool& operator=(const ThreadPool&) = delete;
-
- static void worker_thread(ThreadPool* thread_pool);
-
- std::vector<std::thread> threads_;
- std::vector<std::thread::id> thread_identifiers_;
-
- std::queue<std::function<void()>> task_queue_;
-
- std::unique_ptr<Semaphore> queue_sem_;
- std::unique_ptr<Semaphore> active_sem_;
-
- std::atomic<bool> terminate_;
+ }
+
+ std::vector<std::thread> threads_;
+ std::unordered_map<std::thread::id, std::uint32_t> thread_ids_;
+ Semaphore thread_semaphore_;
+ std::queue<std::function<void()>> queue_;
+ Semaphore queue_semaphore_;
+ std::atomic<bool> terminate_;
};
-}
+} // namespace thread_pool
+
+#endif // THREAD_POOL_THREAD_POOL_HPP_
=====================================
src/thread_pool.cpp deleted
=====================================
@@ -1,88 +0,0 @@
-/*!
- * @file thread_pool.cpp
- *
- * @brief ThreadPool class source file
- */
-
-#include <exception>
-
-#include "thread_pool/thread_pool.hpp"
-
-namespace thread_pool {
-
-std::unique_ptr<Semaphore> createSemaphore(std::uint32_t value) {
- return std::unique_ptr<Semaphore>(new Semaphore(value));
-}
-
-std::unique_ptr<ThreadPool> createThreadPool(std::uint32_t num_threads) {
- if (num_threads == 0) {
- throw std::invalid_argument("[thread_pool::createThreadPool] error: "
- "invalid number of threads!");
- }
- return std::unique_ptr<ThreadPool>(new ThreadPool(num_threads));
-}
-
-Semaphore::Semaphore(std::uint32_t value)
- : value_(value) {
-}
-
-void Semaphore::post() {
- std::unique_lock<std::mutex> lock(mutex_);
- ++value_;
- condition_.notify_one();
-}
-
-void Semaphore::wait() {
- std::unique_lock<std::mutex> lock(mutex_);
- condition_.wait(lock, [&](){ return value_; });
- --value_;
-}
-
-ThreadPool::ThreadPool(std::uint32_t num_threads) {
-
- queue_sem_ = createSemaphore(1);
- active_sem_ = createSemaphore(0);
-
- terminate_ = false;
- for (std::uint32_t i = 0; i < num_threads; ++i) {
- threads_.emplace_back(ThreadPool::worker_thread, this);
- thread_identifiers_.emplace_back(threads_.back().get_id());
- }
-}
-
-ThreadPool::~ThreadPool() {
-
- terminate_ = true;
- for (std::uint32_t i = 0; i < threads_.size(); ++i) {
- active_sem_->post();
- }
- for (auto& it: threads_) {
- it.join();
- }
-}
-
-void ThreadPool::worker_thread(ThreadPool* thread_pool) {
-
- while (true) {
- thread_pool->active_sem_->wait();
-
- if (thread_pool->terminate_) {
- break;
- }
-
- thread_pool->queue_sem_->wait();
-
- auto task = std::move(thread_pool->task_queue_.front());
- thread_pool->task_queue_.pop();
-
- thread_pool->queue_sem_->post();
-
- if (thread_pool->terminate_) {
- break;
- }
-
- task();
- }
-}
-
-}
=====================================
test/semaphore_test.cpp
=====================================
@@ -0,0 +1,37 @@
+// Copyright (c) 2020 Robert Vaser
+
+#include "thread_pool/semaphore.hpp"
+
+#include <thread> // 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
=====================================
test/thread_pool_test.cpp
=====================================
@@ -1,108 +1,66 @@
-/*!
- * @file thread_pool_test.cpp
- *
- * @brief Thread_pool unit test source file
- */
+// Copyright (c) 2020 Robert Vaser
+#include "thread_pool/thread_pool.hpp"
+
+#include <numeric>
#include <unordered_map>
#include <unordered_set>
-#include "thread_pool/thread_pool.hpp"
#include "gtest/gtest.h"
-class ThreadPoolTest: public ::testing::Test {
-public:
- void SetUp() {
- thread_pool = thread_pool::createThreadPool();
- }
-
- void TearDown() {}
-
- std::unique_ptr<thread_pool::ThreadPool> thread_pool;
-};
+namespace thread_pool {
+namespace test {
-TEST(ThreadPoolTest_, CreateThreadPoolError) {
- try {
- auto thread_pool = thread_pool::createThreadPool(0);
- } catch (std::invalid_argument& exception) {
- EXPECT_STREQ(exception.what(), "[thread_pool::createThreadPool] error: "
- "invalid number of threads!");
+TEST(ThreadPoolThreadPoolTest, Submit) {
+ std::function<std::uint32_t(std::uint32_t)> 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<std::future<std::uint32_t>> 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_F(ThreadPoolTest, ParallelCalculation) {
-
- std::vector<std::vector<std::uint32_t>> data(10);
- for (auto& it: data) {
- it.reserve(100000);
- for (std::uint32_t i = 0; i < 100000; ++i) {
- it.push_back(i);
- }
- }
-
- auto do_some_calculation = [](std::vector<std::uint32_t>& src) -> void {
- for (std::uint32_t i = 0; i < src.size() - 1; ++i) {
- src[i] = (src[i] * src[i + 1]) / (src[i] - src[i + 1] * 3);
- }
- };
-
- std::vector<std::future<void>> thread_futures;
- for (std::uint32_t i = 0; i < data.size(); ++i) {
- thread_futures.emplace_back(thread_pool->submit(do_some_calculation,
- std::ref(data[i])));
- }
-
- for (const auto& it: thread_futures) {
- it.wait();
- }
+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<std::future<std::uint32_t>> 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<std::uint32_t> ts;
+ for (auto& it : f) {
+ ts.emplace(it.get());
+ }
+ EXPECT_EQ(tp.num_threads(), ts.size());
}
-TEST_F(ThreadPoolTest, ThreadIdentifiers) {
-
- const auto& identifiers = thread_pool->thread_identifiers();
- std::unordered_map<std::thread::id, std::uint32_t> thread_map;
- std::uint32_t thread_id = 0;
- for (const auto& it: identifiers) {
- thread_map[it] = thread_id++;
- }
-
- EXPECT_EQ(thread_id, thread_map.size());
-
- auto barrier = thread_pool::createSemaphore(0);
- auto checkpoint = thread_pool::createSemaphore(0);
- auto check_thread_id = [&barrier, &checkpoint](
- std::unordered_map<std::thread::id, std::uint32_t>& thread_map) -> std::int32_t {
-
- checkpoint->post();
- barrier->wait();
-
- if (thread_map.count(std::this_thread::get_id()) != 0) {
- return thread_map[std::this_thread::get_id()];
- }
- return -1;
- };
-
- std::vector<std::future<std::int32_t>> thread_futures;
- for (std::uint32_t i = 0; i < thread_id; ++i) {
- thread_futures.emplace_back(thread_pool->submit(check_thread_id,
- std::ref(thread_map)));
- }
-
- for (std::uint32_t i = 0; i < thread_id; ++i) {
- checkpoint->wait();
- }
- for (std::uint32_t i = 0; i < thread_id; ++i) {
- barrier->post();
- }
-
- std::unordered_set<std::int32_t> thread_identifiers;
- for (auto& it: thread_futures) {
- it.wait();
- thread_identifiers.emplace(it.get());
- }
-
- EXPECT_EQ(thread_id, thread_identifiers.size());
- for (std::uint32_t i = 0; i < thread_id; ++i) {
- EXPECT_EQ(1U, thread_identifiers.count(i));
- }
-}
+} // namespace test
+} // namespace thread_pool
View it on GitLab: https://salsa.debian.org/med-team/libthread-pool/-/compare/135cd22841082e6b3872c7d4d3d899944abbb73e...797a99f27912ee47043887ff45679e1bcd38b233
--
View it on GitLab: https://salsa.debian.org/med-team/libthread-pool/-/compare/135cd22841082e6b3872c7d4d3d899944abbb73e...797a99f27912ee47043887ff45679e1bcd38b233
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20210119/24d2574c/attachment-0001.html>
More information about the debian-med-commit
mailing list