Skip to content

Instantly share code, notes, and snippets.

@brandonto
Created September 16, 2016 13:33
Show Gist options
  • Save brandonto/f15630bee4f53976a6bad9238c9fb093 to your computer and use it in GitHub Desktop.
Save brandonto/f15630bee4f53976a6bad9238c9fb093 to your computer and use it in GitHub Desktop.
Basic ThreadPool Implementation
#include <condition_variable>
#include <iostream>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
#include <cstdlib>
#include "Timer.h"
class ThreadPool
{
public:
ThreadPool(int numThreads) :
_stop(false)
{
const int NUM_THREADS = numThreads;
// Create worker threads
std::cout << "ThreadPool::ThreadPool(): Creating worker threads." << std::endl;
for (int i=0; i<NUM_THREADS; i++)
{
_workerThreads.push_back(std::thread(
[this, i](void)
{
//std::function<void()> task;
while (true)
{
std::unique_lock<std::mutex> lock(this->_task_mutex);
// Wake up if notified and either class destructor was
// called or task queue is not empty
this->_task_cv.wait(lock,
[this](void)
{
return this->_stop || !this->_task_queue.empty();
});
std::cout << "Thread " << i << " is woken up." << std::endl;
// Class destructor was called, join thread
if (this->_stop)
{
std::cout << "Thread " << i << " is stopping." << std::endl;
return;
}
// Dequeue and perform task
auto task = this->_task_queue.front();
this->_task_queue.pop();
lock.unlock();
std::cout << "Thread " << i << " is performing task." << std::endl;
task();
}
}
));
}
std::cout << "ThreadPool::ThreadPool(): Finished creating worker threads." << std::endl;
}
~ThreadPool()
{
std::unique_lock<std::mutex> lock(_task_mutex);
// Wake up all worker threads and signal them to stop
std::cout << "ThreadPool::~ThreadPool(): Sending stop thread signals." << std::endl;
_stop = true;
_task_cv.notify_all();
lock.unlock();
// Join all worker threads
std::cout << "ThreadPool::~ThreadPool(): Joining worker threads." << std::endl;
for (auto &thread : _workerThreads)
{
thread.join();
}
std::cout << "ThreadPool::~ThreadPool(): Finished joining threads." << std::endl;
}
void enqueueTask(std::function<void()> task)
{
// Add task to queue
std::unique_lock<std::mutex> lock(_task_mutex);
_task_queue.push(task);
lock.unlock();
// Wake up a worker thread
_task_cv.notify_one();
}
private:
std::vector<std::thread> _workerThreads;
std::queue<std::function<void()>> _task_queue;
std::mutex _task_mutex;
std::condition_variable _task_cv;
bool _stop;
};
//
// Main program
//
int main(int argc, char *argv[])
{
Timer timer;
ThreadPool threadPool(2);
threadPool.enqueueTask(
[](void)
{
Timer timer;
timer.start();
while (timer.getTimeOnTimer() < 2000);
timer.stop();
std::cout << "Task complete." << std::endl;
});
threadPool.enqueueTask(
[](void)
{
std::cout << "Task complete." << std::endl;
});
threadPool.enqueueTask(
[](void)
{
Timer timer;
timer.start();
while (timer.getTimeOnTimer() < 1000);
timer.stop();
std::cout << "Task complete." << std::endl;
});
timer.start();
while (timer.getTimeOnTimer() < 4000);
timer.stop();
return 0;
}
//******************************************************************************
//
// Timer.cpp
//
// Copyright (c) 2016 Brandon To
// This code snippet is licensed under the BSD 3-clause license.
//
// Author: Brandon To
// Created: August 24, 2016
//
//******************************************************************************
#include "Timer.h"
Timer::Timer() :
_startTime(steady_clock::time_point::min()),
_tempTime(steady_clock::time_point::min()),
_pausedTime(steady_clock::time_point::min()),
_started(false),
_paused(false)
{
}
void
Timer::start()
{
if (_started)
{
return;
}
_started = true;
_paused = false;
_startTime = steady_clock::now();
_tempTime = _startTime;
_pausedTime = steady_clock::time_point::min();
}
void
Timer::stop()
{
if (!_started)
{
return;
}
_started = false;
_paused = false;
_startTime = steady_clock::time_point::min();
_tempTime = steady_clock::time_point::min();
_pausedTime = steady_clock::time_point::min();
}
void
Timer::pause()
{
if (!_started || _paused)
{
return;
}
_paused = true;
_pausedTime = steady_clock::now();
}
void
Timer::resume()
{
if (!_started || !_paused)
{
return;
}
_paused = false;
_tempTime = _tempTime + (steady_clock::now() - _pausedTime);
_pausedTime = steady_clock::time_point::min();
}
uint32_t
Timer::getTimeOnTimer()
{
if (!_started)
{
return 0;
}
if (_paused)
{
auto durationOnTimer = _pausedTime - _tempTime;
auto ms = duration_cast<milliseconds>(durationOnTimer);
return ms.count();
}
auto durationOnTimer = steady_clock::now() - _tempTime;
auto ms = duration_cast<milliseconds>(durationOnTimer);
return ms.count();
}
uint32_t
Timer::getTimeSinceTimerStarted()
{
if (!_started)
{
return 0;
}
auto durationSinceTimerStarted = steady_clock::now() - _startTime;
auto ms = duration_cast<milliseconds>(durationSinceTimerStarted);
return ms.count();
}
bool
Timer::isStarted()
{
return _started;
}
bool
Timer::isPaused()
{
return _paused;
}
//******************************************************************************
//
// Timer.h
//
// Copyright (c) 2016 Brandon To
// This code snippet is licensed under the BSD 3-clause license.
//
// Author: Brandon To
// Created: August 24, 2016
//
//******************************************************************************
#ifndef __TIMER_H__
#define __TIMER_H__
#include <chrono>
#include <cstdint>
using namespace std::chrono;
class Timer
{
public:
Timer();
void start();
void stop();
void pause();
void resume();
uint32_t getTimeOnTimer();
uint32_t getTimeSinceTimerStarted();
bool isStarted();
bool isPaused();
private:
steady_clock::time_point _startTime;
steady_clock::time_point _tempTime;
steady_clock::time_point _pausedTime;
bool _started;
bool _paused;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment