Semaphore.h
#pragma once
#include <mutex>
#include <condition_variable>
#include <atomic>
namespace ASYN_WORK_NVR
{
class Semaphore
{
public:
Semaphore();
~Semaphore();
public:
void Wait();
void Signal();
private:
std::condition_variable condition;
std::mutex mutex;
unsigned int wakeups;
std::atomic<int> count;
};
}
Semaphore.cpp
#include "Semaphore.h"
namespace ASYN_WORK_NVR
{
Semaphore::Semaphore()
:count(0)
, wakeups(0)
{
}
Semaphore::~Semaphore()
{
}
void Semaphore::Wait()
{
if (--count < 0)
{
std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [&](){ return wakeups > 0; });
--wakeups;
}
}
void Semaphore::Signal()
{
if (++count < 1)
{
std::unique_lock<std::mutex> lock(mutex);
++wakeups;
condition.notify_one();
}
}
}
Task.h
#pragma once
namespace ASYN_WORK_NVR
{
class CTask
{
public:
CTask(void);
virtual ~CTask(void);
virtual void Do();
virtual void Cancel();
};
}
Task.cpp
#include "Task.h"
namespace ASYN_WORK_NVR
{
CTask::CTask(void) {}
CTask::~CTask(void){}
void CTask::Do(){}
void CTask::Cancel(){}
}
TaskProxy.h
#pragma once
#include <mutex>
#include <thread>
#include <chrono>
#include <functional>
#include "Task.h"
namespace ASYN_WORK_NVR
{
class CTaskProxy : public CTask
{
public:
CTaskProxy(const std::function<void()>& fn);
~CTaskProxy();
public:
void Control(bool canWork);
void Do()override;
void Cancel()override;
private:
std::function<void()> m_fn;
bool m_canWork;
std::mutex m_mutexWork;
};
}
TaskProxy.cpp
#include "TaskProxy.h"
namespace ASYN_WORK_NVR
{
CTaskProxy::CTaskProxy(const std::function<void()>& fn)
:m_fn(fn)
, m_canWork(true)
{
}
CTaskProxy::~CTaskProxy()
{
}
void CTaskProxy::Control(bool canWork)
{
std::unique_lock<std::mutex> lock(m_mutexWork);
m_canWork = canWork;
}
void CTaskProxy::Do()
{
std::unique_lock<std::mutex> lock(m_mutexWork);
if (!m_canWork)
{
return;
}
if (m_fn)
{
m_fn();//不要在m_fn裏面調用Control
}
}
void CTaskProxy::Cancel()
{
Do();
}
}
TaskQueue.h
#pragma once
#include <queue>
#include <mutex>
namespace ASYN_WORK_NVR
{
template<typename T>
class CTaskQueue
{
public:
CTaskQueue(void){}
~CTaskQueue(void){}
public:
void Push(const T& t)
{
std::unique_lock<std::mutex> lock(m_mutexTask);
m_queueTask.push(t);
}
bool Front(T& t)
{
std::unique_lock<std::mutex> lock(m_mutexTask);
if (!m_queueTask.empty())
{
t = m_queueTask.front();
return true;
}
return false;
}
bool Pop(T& t)
{
std::unique_lock<std::mutex> lock(m_mutexTask);
if (!m_queueTask.empty())
{
t = m_queueTask.front();
m_queueTask.pop();
return true;
}
return false;
}
void Swap(std::queue<T>& queueTask)
{
std::unique_lock<std::mutex> lock(m_mutexTask);
m_queueTask.swap(queueTask);
}
unsigned int Size()
{
std::unique_lock<std::mutex> lock(m_mutexTask);
return m_queueTask.size();
}
private:
std::queue<T> m_queueTask;
std::mutex m_mutexTask;
};
}
ThreadPool.h
#pragma once
#include <memory>
#include <thread>
#include <mutex>
#include <vector>
#include "Task.h"
#include "TaskQueue.h"
#include "Semaphore.h"
namespace ASYN_WORK_NVR
{
class CThreadPool
{
public:
CThreadPool(unsigned int num);
~CThreadPool();
void PostTask(const std::shared_ptr<CTask>& pTask);
private:
void Run(void);
void DoTask();
void Cancel();
private:
CTaskQueue<std::shared_ptr<CTask> > m_TaskQueue;
Semaphore m_workSemaphore;
bool m_bExit;
std::vector<std::thread*> m_vecThread;
};
}
ThreadPool.cpp
#include "ThreadPool.h"
#include <algorithm>
#include "INFCoreDll.h"
#include "Common.h"
#ifdef WIN32
#include <windows.h>
#else
#include <sys/time.h>
namespace ASYN_WORK_NVR
{
const unsigned int DEFAULT_POOL_TIME = 20; //ms
CThreadPool::CThreadPool(unsigned int num)
:m_bExit(false)
{
while (num--)
{
m_vecThread.push_back(new std::thread(std::bind(&CThreadPool::Run, this)));
}
}
CThreadPool::~CThreadPool()
{
m_bExit = true;
for (int i = 0; i < m_vecThread.size(); i++)
{
m_workSemaphore.Signal();
}
std::for_each(m_vecThread.begin(), m_vecThread.end(), [&](std::thread* pThread)
{
if (pThread)
{
pThread->join();
delete pThread;
}
});
}
void CThreadPool::Run(void)
{
while (!m_bExit)
{
m_workSemaphore.Wait();
DoTask();
}
Cancel();
}
void CThreadPool::DoTask()
{
std::shared_ptr<CTask> pTask = nullptr;
int queSize = m_TaskQueue.Size();
if (queSize > 10)
{
INFLOG_DBG(M_NVR_X, "CThreadPool::DoTask(), queue size is %03d(>10), for performance.", m_TaskQueue.Size());
}
while (m_TaskQueue.Pop(pTask))
{
if (pTask)
{
pTask->Do();
}
if (m_bExit)
{
INFLOG_DBG(M_NVR_X, "thread pool exit, queue size is %03d.", queSize - 1);
break;
}
queSize--;
int iMS = queSize < 5 ? DEFAULT_POOL_TIME : (queSize < 10 ? (DEFAULT_POOL_TIME + 10) : (DEFAULT_POOL_TIME + 20));
#ifdef WIN32
Sleep(iMS);
#else
usleep(iMS*1000);
#endif
_UTILITY::SleepMS();//performance-def
}
}
void CThreadPool::Cancel()
{
std::shared_ptr<CTask> pTask = nullptr;
while (m_TaskQueue.Pop(pTask))
{
if (pTask)
{
pTask->Cancel();
}
}
}
void CThreadPool::PostTask(const std::shared_ptr<CTask>& pTask)
{
if (pTask)
{
m_TaskQueue.Push(pTask);
m_workSemaphore.Signal();
}
}
}
main.cpp
#include "ThreadPool.h"
#include<iostream>
class CCMSConnecterTask : public ASYN_WORK_NVR::CTask
{
public:
CCMSConnecterTask(){};
~CCMSConnecterTask(){};
void Do()
{
//消息處理
std::cout << "do job" << std::endl;
};
void Cancel()
{
Do();
};
};
int main(void)
{
ASYN_WORK_NVR::CThreadPool* m_pHandlerThreadPool = nullptr;
m_pHandlerThreadPool = new ASYN_WORK_NVR::CThreadPool(8);//線程池創建8個線程
if (m_pHandlerThreadPool)
{
std::shared_ptr<CCMSConnecterTask> pTask(new CCMSConnecterTask());
m_pHandlerThreadPool->PostTask(pTask); //執行任務
}
if (m_pHandlerThreadPool)
{
delete m_pHandlerThreadPool;
m_pHandlerThreadPool = nullptr;
}
return 0;
}