07C++11线程池2
1. 线程池DLL工程
defs.h中定义了导入导出符、单元测试相关宏、错误码等。
//defs.h
#ifndef __ROCK_THREAD_POOL_DEFS_H__
#define __ROCK_THREAD_POOL_DEFS_H__
#if defined WIN32 || defined WIN64
#ifdef THREAD_POOL_DLL_BUILD
#define THREAD_POOL_API _declspec(dllexport)
#elif defined( THREAD_POOL_DLL_USE )
#define THREAD_POOL_API _declspec(dllimport)
#else
#define THREAD_POOL_API
#endif
#else // WIN32
#define THREAD_POOL_API
#endif // WIN32
/// UNIT TEST MACRO
#ifdef __UT_TEST__
#define PUBLIC public
#define PRIVATE public
#define PROTECTED public
#else
#define PUBLIC public
#define PRIVATE private
#define PROTECTED protected
#endif // UT_TEST
#include <memory>
#include <vector>
#include <list>
#include <thread>
#include <functional>
#include <atomic>
#define ROCK_OS_TOOLS_NAMESPACE_BEGIN namespace rock { namespace os_tools {
#define ROCK_OS_TOOLS_NAMESPACE_END } }
ROCK_OS_TOOLS_NAMESPACE_BEGIN
// 错误码
enum ThreadPoolError
{
THREAD_POOL_ERROR_NO = 0,
THREAD_POOL_ERROR_GENERAL = -1
};
ROCK_OS_TOOLS_NAMESPACE_END
#endif // end of ROCK_OS_TOOLS_NAMESPACE_END
线程池接口头文件
//thread_pool.h
#ifndef __ROCK_THREAD_POOL_H__
#define __ROCK_THREAD_POOL_H__
#include "defs.h"
ROCK_OS_TOOLS_NAMESPACE_BEGIN
class THREAD_POOL_API ThreadPool
{
PUBLIC:
const int MAX_TASK_COUNT = 100;
using Task = std::function<void()>;
PUBLIC:
static ThreadPool& instance();
virtual void start(const int& threadCount = std::thread::hardware_concurrency()) = 0;
virtual void stop() = 0;
virtual void addTask(Task&& task) = 0;
virtual void addTask(const Task& task) = 0;
};
typedef std::shared_ptr<ThreadPool> ThreadPoolSPtr;
ROCK_OS_TOOLS_NAMESPACE_END
#endif //__ROCK_THREAD_POOL_H__
线程池接口cpp文件
//thread_pool.cpp
#include "thread_pool_imp.h"
rock::os_tools::ThreadPool& rock::os_tools::ThreadPool::instance()
{
static ThreadPoolImp inst;
return inst;
}
线程池实现头文件
//thread_pool_imp.h
#ifndef __ROCK_THREAD_POOL_IMP_H__
#define __ROCK_THREAD_POOL_IMP_H__
#include "thread_pool.h"
#include "sync_queue.h"
ROCK_OS_TOOLS_NAMESPACE_BEGIN
class ThreadPoolImp : public ThreadPool
{
PUBLIC:
ThreadPoolImp();
~ThreadPoolImp();
virtual void start(const int& threadCount = std::thread::hardware_concurrency()) override;
virtual void stop() override;
virtual void addTask(Task&& task) override;
virtual void addTask(const Task& task) override;
PRIVATE:
void startThreadGroup(const int& threadCount);
void runInThread();
void stopThreadGroup();
std::list<std::shared_ptr<std::thread>> m_threadGroup;
SyncQueue<Task> m_queue;
atomic_bool m_running;
std::once_flag m_flag;
};
ROCK_OS_TOOLS_NAMESPACE_END
#endif //__ROCK_THREAD_POOL_IMP_H__
线程池实现cpp
//thread_pool_imp.cpp
#include "thread_pool_imp.h"
rock::os_tools::ThreadPoolImp::ThreadPoolImp()
:m_queue(MAX_TASK_COUNT)
{
m_running = false;
}
rock::os_tools::ThreadPoolImp::~ThreadPoolImp()
{
stop();
}
void rock::os_tools::ThreadPoolImp::start(const int& threadCount /*= std::thread::hardware_concurrency()*/)
{
if (!m_running)
{
startThreadGroup(threadCount);
}
}
void rock::os_tools::ThreadPoolImp::stop()
{
//std::call_once(m_flag, [this](){stopThreadGroup(); });
if (m_running)
{
stopThreadGroup();
}
}
void rock::os_tools::ThreadPoolImp::addTask(Task&& task)
{
m_queue.put(std::forward<Task>(task));
}
void rock::os_tools::ThreadPoolImp::addTask(const Task& task)
{
m_queue.put(task);
}
void rock::os_tools::ThreadPoolImp::startThreadGroup(const int& threadCount)
{
m_queue.start();
m_running = true;
for (int i = 0; i < threadCount; ++i)
{
m_threadGroup.push_back(std::make_shared<std::thread>(&ThreadPoolImp::runInThread, this));
}
}
void rock::os_tools::ThreadPoolImp::runInThread()
{
while (m_running)
{
Task task;
m_queue.take(task);
if (!m_running)
{
return;
}
if (task)
{
task();
}
}
}
void rock::os_tools::ThreadPoolImp::stopThreadGroup()
{
m_queue.stop();
m_running = false;
for (auto& thread : m_threadGroup)
{
if (thread)
{
thread->join();
}
}
m_threadGroup.clear();
}
gtest单元测试main文件
//ut_main.cpp
#include "gtest/gtest.h"
#include "gmock/gmock.h"
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
gtest单元测试文件
//ut_thread_pool.cpp
#include "gtest/gtest.h"
#include "thread_pool.h"
using namespace rock::os_tools;
using namespace std;
class ThreadPoolTest : public testing::Test
{
public:
ThreadPoolTest():m_pool(ThreadPool::instance())
{
}
~ThreadPoolTest()
{
m_pool.stop();
}
virtual void SetUp()
{
}
virtual void TearDown()
{
m_pool.stop();
}
protected:
ThreadPool& m_pool;
};
TEST_F(ThreadPoolTest, 001_instance_1)
{
m_pool.start(1);
for (int i = 0; i < 10; ++i)
{
//因为这个地方可以使用lamda表达式捕获参数,所以Task定义成无参类型是合理的。
m_pool.addTask([i]{
cout << "doing tast:" << i << " in thread " << this_thread::get_id() << endl;
this_thread::sleep_for(std::chrono::seconds(1));
});
}
this_thread::sleep_for(std::chrono::seconds(11));
}
TEST_F(ThreadPoolTest, 001_instance_2)
{
m_pool.start(2);
for (int i = 0; i < 10; ++i)
{
//因为这个地方可以使用lamda表达式捕获参数,所以Task定义成无参类型是合理的。
m_pool.addTask([i]{
cout << "doing tast:" << i << " in thread " << this_thread::get_id() << endl;
this_thread::sleep_for(std::chrono::seconds(1));
});
}
this_thread::sleep_for(std::chrono::seconds(6));
}
TEST_F(ThreadPoolTest, 001_instance_4)
{
m_pool.start(4);
for (int i = 0; i < 10; ++i)
{
//因为这个地方可以使用lamda表达式捕获参数,所以Task定义成无参类型是合理的。
m_pool.addTask([i]{
cout << "doing tast:" << i << " in thread " << this_thread::get_id() << endl;
this_thread::sleep_for(std::chrono::seconds(1));
});
}
this_thread::sleep_for(std::chrono::seconds(6));
}
TEST_F(ThreadPoolTest, 001_instance_5)
{
m_pool.start(4);
for (int i = 0; i < 20; ++i)
{
//因为这个地方可以使用lamda表达式捕获参数,所以Task定义成无参类型是合理的。
m_pool.addTask([i]{
cout << "doing tast:" << i << " in thread " << this_thread::get_id() << endl;
this_thread::sleep_for(std::chrono::seconds(1));
});
}
this_thread::sleep_for(std::chrono::seconds(6));
}
道虽迩,不行不至;事虽小,不为不成。