First commit with a tested version of the thread pool
This commit is contained in:
commit
20f6a9a8fd
73
.gitignore
vendored
Normal file
73
.gitignore
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(ThreadPool)
|
||||
add_library(threadpool_lib "src/ThreadPool.cpp")
|
||||
|
||||
add_executable(${PROJECT_NAME} "main.cpp")
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} threadpool_lib)
|
1
include/ThreadPool.cpp
Normal file
1
include/ThreadPool.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "ThreadPool.h"
|
98
include/ThreadPool.h
Normal file
98
include/ThreadPool.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef THREADPOOL_H
|
||||
#define THREADPOOL_H
|
||||
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
class ThreadPool {
|
||||
int numOfThreads;
|
||||
std::deque<std::function<void()>> _tasks;
|
||||
std::mutex _queueLock;
|
||||
std::atomic<bool> stopped{false};
|
||||
bool startedAlready = false;
|
||||
std::condition_variable _queueCond;
|
||||
std::condition_variable _threadFinishedCond;
|
||||
std::atomic_int numOfThreadsRunning{0};
|
||||
std::vector<std::thread> _threads;
|
||||
|
||||
protected:
|
||||
inline void threadWorker();
|
||||
inline void joinAll();
|
||||
|
||||
public:
|
||||
inline ThreadPool();
|
||||
inline ~ThreadPool();
|
||||
inline void push(const std::function<void()> &task);
|
||||
inline void
|
||||
start(const int NumOfThreads = std::thread::hardware_concurrency());
|
||||
inline void finish();
|
||||
};
|
||||
|
||||
void ThreadPool::threadWorker() {
|
||||
while (true) {
|
||||
std::unique_lock<decltype(_queueLock)> lg(_queueLock);
|
||||
while (_tasks.empty() && !stopped.load()) {
|
||||
_queueCond.wait(lg);
|
||||
}
|
||||
if (!_tasks.empty()) {
|
||||
auto theTask = _tasks[0];
|
||||
_tasks.pop_front();
|
||||
lg.unlock();
|
||||
theTask();
|
||||
lg.lock();
|
||||
}
|
||||
if (_tasks.empty() && stopped.load()) {
|
||||
numOfThreadsRunning--;
|
||||
_threadFinishedCond.notify_one();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::joinAll() {
|
||||
for (long i = 0; i < numOfThreads; i++) {
|
||||
if (_threads[i].joinable())
|
||||
_threads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPool::ThreadPool() {}
|
||||
|
||||
ThreadPool::~ThreadPool() { this->finish(); }
|
||||
|
||||
void ThreadPool::push(const std::function<void()> &task) {
|
||||
std::unique_lock<decltype(_queueLock)> lg(_queueLock);
|
||||
_tasks.push_back(task);
|
||||
lg.unlock();
|
||||
_queueCond.notify_one();
|
||||
}
|
||||
|
||||
void ThreadPool::start(const int NumOfThreads) {
|
||||
if (!startedAlready)
|
||||
startedAlready = true;
|
||||
else
|
||||
throw std::logic_error("You cannot start the thread pool multiple times.");
|
||||
numOfThreads = NumOfThreads;
|
||||
_threads.reserve(numOfThreads);
|
||||
for (long i = 0; i < numOfThreads; i++) {
|
||||
_threads.push_back(std::thread(std::bind(&ThreadPool::threadWorker, this)));
|
||||
numOfThreadsRunning++;
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::finish() {
|
||||
std::unique_lock<decltype(_queueLock)> lg(_queueLock);
|
||||
stopped.store(true);
|
||||
_queueCond.notify_all();
|
||||
while (numOfThreadsRunning > 0) {
|
||||
_threadFinishedCond.wait(lg);
|
||||
}
|
||||
lg.unlock();
|
||||
joinAll();
|
||||
}
|
||||
|
||||
#endif // THREADPOOL_H
|
55
main.cpp
Normal file
55
main.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "src/ThreadPool.h"
|
||||
|
||||
void SumZeroToNumber(long &num) {
|
||||
long val = 0;
|
||||
for (long i = 0; i <= static_cast<long>(num); i++) {
|
||||
val += i;
|
||||
}
|
||||
static_cast<long>(num) = val;
|
||||
}
|
||||
|
||||
int main() {
|
||||
for (int tries = 0; tries < 10; tries++) {
|
||||
std::cout << "Try number: " << tries + 1 << "... ";
|
||||
|
||||
std::vector<long> nums(100000);
|
||||
std::vector<long> numsResults(nums.size());
|
||||
std::vector<long> numsSequentialResults(nums.size());
|
||||
try {
|
||||
ThreadPool pool; // num of cores
|
||||
pool.start();
|
||||
for (unsigned i = 0; i < nums.size(); i++) {
|
||||
nums[i] = rand() % 1000;
|
||||
numsResults[i] = nums[i];
|
||||
numsSequentialResults[i] = nums[i];
|
||||
// this is just a copy to be passed and
|
||||
// modified, while the original remains
|
||||
// unchanged
|
||||
pool.push(std::bind(SumZeroToNumber, std::ref(numsResults[i])));
|
||||
}
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
pool.finish();
|
||||
} catch (std::exception &ex) {
|
||||
std::cout
|
||||
<< "An exception was thrown while processing data. Exception says: "
|
||||
<< ex.what() << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
// test results sequentially
|
||||
for (unsigned i = 0; i < nums.size(); i++) {
|
||||
SumZeroToNumber(numsSequentialResults[i]);
|
||||
if (numsSequentialResults[i] != numsResults[i]) {
|
||||
std::cout << "failed." << std::endl;
|
||||
std::cout << "Comparing " << numsSequentialResults[i] << " with "
|
||||
<< numsResults[i] << " failed." << std::endl;
|
||||
throw std::runtime_error("Results didn't match!");
|
||||
}
|
||||
}
|
||||
std::cout << "succeeded." << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "End of program reached." << std::endl;
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user