blob: 32557a86720d8f6c96eb8bd61dc23e65ccabb469 [file]
/**
* Copyright (C) 2013 kangliqiang ,kangliq@163.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ThreadPool.h"
#include "RocketMQClient.h"
#include "ScopedLock.h"
#include "KPRUtil.h"
namespace kpr
{
ThreadPoolWorker:: ThreadPoolWorker(ThreadPool* pThreadPool, const char* strName)
: kpr::Thread(strName),
m_pThreadPool(pThreadPool),
m_canWork(false),
m_isWaiting(false),
m_stop(false),
m_idleTime(0),
m_idle(true)
{
}
bool ThreadPoolWorker::IsIdle()
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
return m_idle;
}
void ThreadPoolWorker:: SetIdle(bool idle)
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
m_idle = idle;
m_idleTime = 0;
}
int ThreadPoolWorker::IdleTime(int idleTime)
{
if (m_idle)
{
m_idleTime += idleTime;
}
else
{
m_idleTime = 0;
}
return m_idleTime;
}
void ThreadPoolWorker::Run()
{
while (!m_stop)
{
SetIdle(true);
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
while (!m_canWork)
{
try
{
m_isWaiting = true;
Wait();
m_isWaiting = false;
}
catch (...)
{
}
}
m_canWork = false;
}
while (!m_stop)
{
ThreadPoolWorkPtr request = m_pThreadPool->GetWork(this);
if ((ThreadPoolWork*)(NULL) == request)
{
break;
}
SetIdle(false);
try
{
request->Do();
}
catch(...)
{
RMQ_ERROR("thead[%s] doWork exception", GetName());
}
//delete request;
request = NULL;
}
if (m_stop || m_pThreadPool->IsDestroy())
{
break;
}
}
m_pThreadPool ->RemoveThread(this);
m_pThreadPool = NULL;
}
void ThreadPoolWorker::WakeUp()
{
SetIdle(false);
kpr::ScopedLock<kpr::Monitor> lock(*this);
m_canWork = true;
Notify();
}
void ThreadPoolWorker::Stop()
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
m_canWork = true;
m_stop = true;
Notify();
}
bool ThreadPoolWorker:: IsWaiting()
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
return m_isWaiting;
}
ThreadPool::ThreadPool(const char* name,
int count,
int minCount,
int maxCount,
int step,
int maxIdleTime,
int checkldleThreadsInterval)
{
if (name == NULL)
{
snprintf(m_name, sizeof(m_name), "ThreadPool");
}
else
{
snprintf(m_name, sizeof(m_name), "%s", name);
}
m_destroy = false;
m_minCount = minCount;
m_maxCount = maxCount;
m_maxIdleTime = maxIdleTime;
m_count = 0;
m_step = step;
m_index = 0;
m_lastRemoveIdleThreadsTime = KPRUtil::GetCurrentTimeMillis();
if (m_minCount <= 0)
{
m_minCount = MIN_THREAD_COUNT;
}
if (m_maxCount < 0)
{
m_maxCount = MAX_THREAD_COUNT;
}
if (m_maxIdleTime < 0)
{
m_maxIdleTime = MAX_IDLE_THREAD_TIME;
}
if (m_maxCount != 0 && m_maxCount < m_minCount)
{
m_minCount = MIN_THREAD_COUNT;
}
if ((m_maxCount != 0 && count > m_maxCount) || count < m_minCount)
{
count = m_minCount;
}
if (checkldleThreadsInterval < 0)
{
checkldleThreadsInterval = CHECK_IDLE_THREADS_INTERVAL;
}
AddThreads(count);
char manager_name[32];
snprintf(manager_name, sizeof(manager_name), "%s-manager", m_name);
m_manager = new ThreadPoolManage(manager_name, this, checkldleThreadsInterval);
m_manager->Start();
}
ThreadPool::~ThreadPool()
{
Destroy();
}
void ThreadPool::AddThreads(int count)
{
char threadName[256];
for (int i = 0; i < count; ++i)
{
snprintf(threadName, sizeof(threadName), "%s-Worker%d", m_name, m_index);
try
{
ThreadPoolWorkerPtr worker = new ThreadPoolWorker(this, threadName);
worker->Start();
m_workers.push_back(worker);
while (!worker->IsWaiting())
{
kpr::Thread::Sleep(0, 100000);
}
m_index++;
m_count++;
}
catch (...)
{
RMQ_ERROR("ThreadPool thead[%s] new exception", threadName);
}
}
}
void ThreadPool::Destroy()
{
std::list<ThreadPoolWorkerPtr> workers;
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
if (m_destroy)
{
return;
}
m_destroy = true;
std::list<ThreadPoolWorkerPtr>::iterator iter;
for (iter = m_workers.begin(); iter != m_workers.end(); iter++)
{
workers.push_back(*iter);
(*iter)->Stop();
}
}
m_manager->Stop();
m_manager->Join();
std::list<ThreadPoolWorkerPtr>::iterator itThread;
for (itThread = workers.begin(); itThread != workers.end(); itThread++)
{
(*itThread)->Join();
}
m_works.clear();
}
int ThreadPool::AddWork(ThreadPoolWorkPtr pWork)
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
if (m_destroy)
{
return -1;
}
m_works.push_back(pWork);
if (!WakeOneThread())
{
if (0 == m_maxCount || m_count < m_maxCount)
{
int step = m_step;
if (0 < m_maxCount && m_count + m_step > m_maxCount)
{
step = m_maxCount - m_count;
}
AddThreads(step);
WakeOneThread();
}
}
return 0;
}
ThreadPoolWorkPtr ThreadPool::GetWork(ThreadPoolWorker* pWorker)
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
ThreadPoolWorkPtr result = NULL;
if (!m_destroy && !m_works.empty())
{
result = m_works.front();
m_works.pop_front();
}
return result;
}
bool ThreadPool::IsDestroy()
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
return m_destroy;
}
void ThreadPool::RemoveThread(ThreadPoolWorker* workerThread)
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
std::list<ThreadPoolWorkerPtr>::iterator it = m_workers.begin();
for (; it != m_workers.end(); it++)
{
if ((*it) == workerThread)
{
m_workers.erase(it);
m_count--;
break;
}
}
}
void ThreadPool::RemoveIdleThreads()
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
if (m_maxIdleTime == 0)
{
return;
}
unsigned long long time = KPRUtil::GetCurrentTimeMillis();
int interval = (int)(time - m_lastRemoveIdleThreadsTime);
m_lastRemoveIdleThreadsTime = time;
std::list<ThreadPoolWorkerPtr>::iterator it = m_workers.begin();
int size = (int)m_workers.size();
while (size > m_minCount && it != m_workers.end())
{
if ((*it)->IdleTime(interval) > m_maxIdleTime)
{
(*it)->Stop();
size--;
}
it++;
}
}
bool ThreadPool::WakeOneThread()
{
std::list<ThreadPoolWorkerPtr>::iterator it = m_workers.begin();
for (; it != m_workers.end(); it++)
{
if ((*it)->IsIdle())
{
(*it)->WakeUp();
return true;
}
}
return false;
}
ThreadPoolManage::ThreadPoolManage(const char* name, ThreadPool* pThreadPool, int checkldleThreadsInterval)
: kpr::Thread(name),
m_pThreadPool(pThreadPool),
m_stop(false),
m_checkIdleThreadsInterval(checkldleThreadsInterval)
{
}
ThreadPoolManage::~ThreadPoolManage()
{
}
void ThreadPoolManage::Stop()
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
m_stop = true;
Notify();
}
void ThreadPoolManage::Run()
{
while (!m_stop)
{
{
kpr::ScopedLock<kpr::Monitor> lock(*this);
if (!m_stop)
{
Wait(m_checkIdleThreadsInterval);
}
if (m_stop)
{
break;
}
}
m_pThreadPool->RemoveIdleThreads();
}
}
}