You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-07-29 08:21:15 +03:00
Reformat all code to coding standard
This commit is contained in:
@ -37,144 +37,162 @@ namespace threadpool
|
||||
{
|
||||
|
||||
PriorityThreadPool::PriorityThreadPool(uint targetWeightPerRun, uint highThreads,
|
||||
uint midThreads, uint lowThreads, uint ID) :
|
||||
_stop(false), weightPerRun(targetWeightPerRun), id(ID)
|
||||
uint midThreads, uint lowThreads, uint ID) :
|
||||
_stop(false), weightPerRun(targetWeightPerRun), id(ID)
|
||||
{
|
||||
for (uint32_t i = 0; i < highThreads; i++)
|
||||
threads.create_thread(ThreadHelper(this, HIGH));
|
||||
for (uint32_t i = 0; i < midThreads; i++)
|
||||
threads.create_thread(ThreadHelper(this, MEDIUM));
|
||||
for (uint32_t i = 0; i < lowThreads; i++)
|
||||
threads.create_thread(ThreadHelper(this, LOW));
|
||||
cout << "started " << highThreads << " high, " << midThreads << " med, " << lowThreads
|
||||
<< " low.\n";
|
||||
threadCounts[HIGH] = highThreads;
|
||||
threadCounts[MEDIUM] = midThreads;
|
||||
threadCounts[LOW] = lowThreads;
|
||||
for (uint32_t i = 0; i < highThreads; i++)
|
||||
threads.create_thread(ThreadHelper(this, HIGH));
|
||||
|
||||
for (uint32_t i = 0; i < midThreads; i++)
|
||||
threads.create_thread(ThreadHelper(this, MEDIUM));
|
||||
|
||||
for (uint32_t i = 0; i < lowThreads; i++)
|
||||
threads.create_thread(ThreadHelper(this, LOW));
|
||||
|
||||
cout << "started " << highThreads << " high, " << midThreads << " med, " << lowThreads
|
||||
<< " low.\n";
|
||||
threadCounts[HIGH] = highThreads;
|
||||
threadCounts[MEDIUM] = midThreads;
|
||||
threadCounts[LOW] = lowThreads;
|
||||
}
|
||||
|
||||
PriorityThreadPool::~PriorityThreadPool()
|
||||
{
|
||||
stop();
|
||||
stop();
|
||||
}
|
||||
|
||||
void PriorityThreadPool::addJob(const Job &job, bool useLock)
|
||||
void PriorityThreadPool::addJob(const Job& job, bool useLock)
|
||||
{
|
||||
mutex::scoped_lock lk(mutex, defer_lock_t());
|
||||
mutex::scoped_lock lk(mutex, defer_lock_t());
|
||||
|
||||
if (useLock)
|
||||
lk.lock();
|
||||
if (useLock)
|
||||
lk.lock();
|
||||
|
||||
if (job.priority > 66)
|
||||
jobQueues[HIGH].push_back(job);
|
||||
else if (job.priority > 33)
|
||||
jobQueues[MEDIUM].push_back(job);
|
||||
else
|
||||
jobQueues[LOW].push_back(job);
|
||||
if (job.priority > 66)
|
||||
jobQueues[HIGH].push_back(job);
|
||||
else if (job.priority > 33)
|
||||
jobQueues[MEDIUM].push_back(job);
|
||||
else
|
||||
jobQueues[LOW].push_back(job);
|
||||
|
||||
if (useLock)
|
||||
newJob.notify_one();
|
||||
if (useLock)
|
||||
newJob.notify_one();
|
||||
}
|
||||
|
||||
void PriorityThreadPool::removeJobs(uint32_t id)
|
||||
{
|
||||
list<Job>::iterator it;
|
||||
list<Job>::iterator it;
|
||||
|
||||
mutex::scoped_lock lk(mutex);
|
||||
mutex::scoped_lock lk(mutex);
|
||||
|
||||
for (uint32_t i = 0; i < _COUNT; i++)
|
||||
for (it = jobQueues[i].begin(); it != jobQueues[i].end();)
|
||||
if (it->id == id)
|
||||
it = jobQueues[i].erase(it);
|
||||
else
|
||||
++it;
|
||||
for (uint32_t i = 0; i < _COUNT; i++)
|
||||
for (it = jobQueues[i].begin(); it != jobQueues[i].end();)
|
||||
if (it->id == id)
|
||||
it = jobQueues[i].erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
PriorityThreadPool::Priority PriorityThreadPool::pickAQueue(Priority preference)
|
||||
{
|
||||
if (!jobQueues[preference].empty())
|
||||
return preference;
|
||||
else if (!jobQueues[HIGH].empty())
|
||||
return HIGH;
|
||||
else if (!jobQueues[MEDIUM].empty())
|
||||
return MEDIUM;
|
||||
else
|
||||
return LOW;
|
||||
if (!jobQueues[preference].empty())
|
||||
return preference;
|
||||
else if (!jobQueues[HIGH].empty())
|
||||
return HIGH;
|
||||
else if (!jobQueues[MEDIUM].empty())
|
||||
return MEDIUM;
|
||||
else
|
||||
return LOW;
|
||||
}
|
||||
|
||||
void PriorityThreadPool::threadFcn(const Priority preferredQueue) throw()
|
||||
{
|
||||
Priority queue;
|
||||
uint32_t weight, i;
|
||||
vector<Job> runList;
|
||||
vector<bool> reschedule;
|
||||
uint32_t rescheduleCount;
|
||||
uint32_t queueSize;
|
||||
Priority queue;
|
||||
uint32_t weight, i;
|
||||
vector<Job> runList;
|
||||
vector<bool> reschedule;
|
||||
uint32_t rescheduleCount;
|
||||
uint32_t queueSize;
|
||||
|
||||
while (!_stop) {
|
||||
while (!_stop)
|
||||
{
|
||||
|
||||
mutex::scoped_lock lk(mutex);
|
||||
mutex::scoped_lock lk(mutex);
|
||||
|
||||
queue = pickAQueue(preferredQueue);
|
||||
if (jobQueues[queue].empty()) {
|
||||
newJob.wait(lk);
|
||||
continue;
|
||||
}
|
||||
queue = pickAQueue(preferredQueue);
|
||||
|
||||
queueSize = jobQueues[queue].size();
|
||||
weight = 0;
|
||||
// 3 conditions stop this thread from grabbing all jobs in the queue
|
||||
//
|
||||
// 1: The weight limit has been exceeded
|
||||
// 2: The queue is empty
|
||||
// 3: It has grabbed more than half of the jobs available &
|
||||
// should leave some to the other threads
|
||||
if (jobQueues[queue].empty())
|
||||
{
|
||||
newJob.wait(lk);
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((weight < weightPerRun) && (!jobQueues[queue].empty())
|
||||
&& (runList.size() <= queueSize/2)) {
|
||||
runList.push_back(jobQueues[queue].front());
|
||||
jobQueues[queue].pop_front();
|
||||
weight += runList.back().weight;
|
||||
}
|
||||
lk.unlock();
|
||||
queueSize = jobQueues[queue].size();
|
||||
weight = 0;
|
||||
// 3 conditions stop this thread from grabbing all jobs in the queue
|
||||
//
|
||||
// 1: The weight limit has been exceeded
|
||||
// 2: The queue is empty
|
||||
// 3: It has grabbed more than half of the jobs available &
|
||||
// should leave some to the other threads
|
||||
|
||||
reschedule.resize(runList.size());
|
||||
rescheduleCount = 0;
|
||||
for (i = 0; i < runList.size() && !_stop; i++) {
|
||||
try {
|
||||
reschedule[i] = false;
|
||||
reschedule[i] = (*(runList[i].functor))();
|
||||
if (reschedule[i])
|
||||
rescheduleCount++;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
cerr << e.what() << endl;
|
||||
}
|
||||
}
|
||||
while ((weight < weightPerRun) && (!jobQueues[queue].empty())
|
||||
&& (runList.size() <= queueSize / 2))
|
||||
{
|
||||
runList.push_back(jobQueues[queue].front());
|
||||
jobQueues[queue].pop_front();
|
||||
weight += runList.back().weight;
|
||||
}
|
||||
|
||||
// no real work was done, prevent intensive busy waiting
|
||||
if (rescheduleCount == runList.size())
|
||||
usleep(1000);
|
||||
lk.unlock();
|
||||
|
||||
if (rescheduleCount > 0) {
|
||||
lk.lock();
|
||||
for (i = 0; i < runList.size(); i++)
|
||||
if (reschedule[i])
|
||||
addJob(runList[i], false);
|
||||
if (rescheduleCount > 1)
|
||||
newJob.notify_all();
|
||||
else
|
||||
newJob.notify_one();
|
||||
lk.unlock();
|
||||
}
|
||||
runList.clear();
|
||||
}
|
||||
reschedule.resize(runList.size());
|
||||
rescheduleCount = 0;
|
||||
|
||||
for (i = 0; i < runList.size() && !_stop; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
reschedule[i] = false;
|
||||
reschedule[i] = (*(runList[i].functor))();
|
||||
|
||||
if (reschedule[i])
|
||||
rescheduleCount++;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// no real work was done, prevent intensive busy waiting
|
||||
if (rescheduleCount == runList.size())
|
||||
usleep(1000);
|
||||
|
||||
if (rescheduleCount > 0)
|
||||
{
|
||||
lk.lock();
|
||||
|
||||
for (i = 0; i < runList.size(); i++)
|
||||
if (reschedule[i])
|
||||
addJob(runList[i], false);
|
||||
|
||||
if (rescheduleCount > 1)
|
||||
newJob.notify_all();
|
||||
else
|
||||
newJob.notify_one();
|
||||
|
||||
lk.unlock();
|
||||
}
|
||||
|
||||
runList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void PriorityThreadPool::stop()
|
||||
{
|
||||
_stop = true;
|
||||
threads.join_all();
|
||||
_stop = true;
|
||||
threads.join_all();
|
||||
}
|
||||
|
||||
} // namespace threadpool
|
||||
|
@ -44,30 +44,33 @@ class PriorityThreadPool
|
||||
{
|
||||
public:
|
||||
|
||||
class Functor {
|
||||
public:
|
||||
virtual ~Functor() { };
|
||||
// as of 12/3/13, all implementors return 0 and -1. -1 will cause
|
||||
class Functor
|
||||
{
|
||||
public:
|
||||
virtual ~Functor() { };
|
||||
// as of 12/3/13, all implementors return 0 and -1. -1 will cause
|
||||
// this thread pool to reschedule the job, 0 will throw it away on return.
|
||||
virtual int operator()() = 0;
|
||||
};
|
||||
virtual int operator()() = 0;
|
||||
};
|
||||
|
||||
//typedef boost::function0<int> Functor;
|
||||
|
||||
struct Job {
|
||||
Job() : weight(1), priority(0), id(0) { }
|
||||
boost::shared_ptr<Functor> functor;
|
||||
uint32_t weight;
|
||||
uint32_t priority;
|
||||
uint32_t id;
|
||||
};
|
||||
struct Job
|
||||
{
|
||||
Job() : weight(1), priority(0), id(0) { }
|
||||
boost::shared_ptr<Functor> functor;
|
||||
uint32_t weight;
|
||||
uint32_t priority;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
enum Priority {
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
_COUNT
|
||||
};
|
||||
enum Priority
|
||||
{
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
_COUNT
|
||||
};
|
||||
|
||||
/*********************************************
|
||||
* ctor/dtor
|
||||
@ -78,11 +81,11 @@ public:
|
||||
*/
|
||||
|
||||
PriorityThreadPool(uint targetWeightPerRun, uint highThreads, uint midThreads,
|
||||
uint lowThreads, uint id = 0);
|
||||
uint lowThreads, uint id = 0);
|
||||
virtual ~PriorityThreadPool();
|
||||
|
||||
void removeJobs(uint32_t id);
|
||||
void addJob(const Job &job, bool useLock = true);
|
||||
void addJob(const Job& job, bool useLock = true);
|
||||
void stop();
|
||||
|
||||
/** @brief for use in debugging
|
||||
@ -92,16 +95,20 @@ public:
|
||||
protected:
|
||||
|
||||
private:
|
||||
struct ThreadHelper {
|
||||
ThreadHelper(PriorityThreadPool *impl, Priority queue) : ptp(impl), preferredQueue(queue) { }
|
||||
void operator()() { ptp->threadFcn(preferredQueue); }
|
||||
PriorityThreadPool *ptp;
|
||||
struct ThreadHelper
|
||||
{
|
||||
ThreadHelper(PriorityThreadPool* impl, Priority queue) : ptp(impl), preferredQueue(queue) { }
|
||||
void operator()()
|
||||
{
|
||||
ptp->threadFcn(preferredQueue);
|
||||
}
|
||||
PriorityThreadPool* ptp;
|
||||
Priority preferredQueue;
|
||||
};
|
||||
|
||||
explicit PriorityThreadPool();
|
||||
explicit PriorityThreadPool(const PriorityThreadPool &);
|
||||
PriorityThreadPool & operator=(const PriorityThreadPool &);
|
||||
explicit PriorityThreadPool(const PriorityThreadPool&);
|
||||
PriorityThreadPool& operator=(const PriorityThreadPool&);
|
||||
|
||||
Priority pickAQueue(Priority preference);
|
||||
void threadFcn(const Priority preferredQueue) throw();
|
||||
|
@ -66,11 +66,11 @@ private:
|
||||
}
|
||||
|
||||
foo(int i):
|
||||
fData(i)
|
||||
{}
|
||||
fData(i)
|
||||
{}
|
||||
|
||||
foo(const foo& copy)
|
||||
: fData(copy.fData)
|
||||
: fData(copy.fData)
|
||||
{}
|
||||
|
||||
int fData;
|
||||
@ -116,10 +116,10 @@ CPPUNIT_TEST_SUITE_REGISTRATION( ThreadPoolTestSuite );
|
||||
#include <cppunit/ui/text/TestRunner.h>
|
||||
|
||||
|
||||
int main( int argc, char **argv)
|
||||
int main( int argc, char** argv)
|
||||
{
|
||||
CppUnit::TextUi::TestRunner runner;
|
||||
CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry();
|
||||
CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
|
||||
runner.addTest( registry.makeTest() );
|
||||
bool wasSuccessful = runner.run( "", false );
|
||||
return (wasSuccessful ? 0 : 1);
|
||||
|
@ -36,13 +36,13 @@ namespace threadpool
|
||||
{
|
||||
|
||||
ThreadPool::ThreadPool()
|
||||
:fMaxThreads( 0 ), fQueueSize( 0 )
|
||||
: fMaxThreads( 0 ), fQueueSize( 0 )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
ThreadPool::ThreadPool( size_t maxThreads, size_t queueSize )
|
||||
:fMaxThreads( maxThreads ), fQueueSize( queueSize )
|
||||
: fMaxThreads( maxThreads ), fQueueSize( queueSize )
|
||||
{
|
||||
init();
|
||||
}
|
||||
@ -70,7 +70,7 @@ void ThreadPool::init()
|
||||
fDebug = false;
|
||||
fStop = false;
|
||||
fNextFunctor = fWaitingFunctors.end();
|
||||
fNextHandle=1;
|
||||
fNextHandle = 1;
|
||||
}
|
||||
|
||||
void ThreadPool::setQueueSize(size_t queueSize)
|
||||
@ -117,19 +117,23 @@ void ThreadPool::join(uint64_t thrHandle)
|
||||
Container_T::iterator iter;
|
||||
Container_T::iterator end = fWaitingFunctors.end();
|
||||
bool foundit = false;
|
||||
|
||||
for (iter = fWaitingFunctors.begin(); iter != end; ++iter)
|
||||
{
|
||||
foundit = false;
|
||||
|
||||
if (iter->hndl == thrHandle)
|
||||
{
|
||||
foundit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fThreadAvailable.wait(lock1);
|
||||
}
|
||||
}
|
||||
@ -143,11 +147,13 @@ void ThreadPool::join(std::vector<uint64_t>& thrHandle)
|
||||
Container_T::iterator iter;
|
||||
Container_T::iterator end = fWaitingFunctors.end();
|
||||
bool foundit = false;
|
||||
|
||||
for (iter = fWaitingFunctors.begin(); iter != end; ++iter)
|
||||
{
|
||||
foundit = false;
|
||||
std::vector<uint64_t>::iterator thrIter;
|
||||
std::vector<uint64_t>::iterator thrEnd = thrHandle.end();
|
||||
|
||||
for (thrIter = thrHandle.begin(); thrIter != thrEnd; ++thrIter)
|
||||
{
|
||||
if (iter->hndl == *thrIter)
|
||||
@ -156,24 +162,28 @@ void ThreadPool::join(std::vector<uint64_t>& thrHandle)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundit == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find any of the handles, then all are complete
|
||||
if (!foundit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fThreadAvailable.wait(lock1);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ThreadPool::invoke(const Functor_T &threadfunc)
|
||||
uint64_t ThreadPool::invoke(const Functor_T& threadfunc)
|
||||
{
|
||||
boost::mutex::scoped_lock lock1(fMutex);
|
||||
uint64_t thrHandle=0;
|
||||
uint64_t thrHandle = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
try
|
||||
@ -208,7 +218,7 @@ uint64_t ThreadPool::invoke(const Functor_T &threadfunc)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "invoke: Starting thread " << fThreadCount << " max " << fMaxThreads
|
||||
<< " queue " << fQueueSize;
|
||||
<< " queue " << fQueueSize;
|
||||
logging::Message::Args args;
|
||||
logging::Message message(0);
|
||||
args.add(oss.str());
|
||||
@ -247,6 +257,7 @@ uint64_t ThreadPool::invoke(const Functor_T &threadfunc)
|
||||
logging::MessageLog ml(lid);
|
||||
ml.logWarningMessage( message );
|
||||
}
|
||||
|
||||
fThreadAvailable.wait(lock1);
|
||||
}
|
||||
catch (...)
|
||||
@ -265,7 +276,8 @@ void ThreadPool::beginThread() throw()
|
||||
try
|
||||
{
|
||||
boost::mutex::scoped_lock lock1(fMutex);
|
||||
boost::system_time timeout = boost::get_system_time()+boost::posix_time::minutes(10);
|
||||
boost::system_time timeout = boost::get_system_time() + boost::posix_time::minutes(10);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (fStop)
|
||||
@ -290,7 +302,8 @@ void ThreadPool::beginThread() throw()
|
||||
--fThreadCount;
|
||||
return;
|
||||
}
|
||||
timeout = boost::get_system_time()+boost::posix_time::minutes(10);
|
||||
|
||||
timeout = boost::get_system_time() + boost::posix_time::minutes(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -302,11 +315,12 @@ void ThreadPool::beginThread() throw()
|
||||
Container_T::iterator todo = fNextFunctor++;
|
||||
++fIssued;
|
||||
lock1.unlock();
|
||||
|
||||
try
|
||||
{
|
||||
todo->functor();
|
||||
}
|
||||
catch (exception &e)
|
||||
catch (exception& e)
|
||||
{
|
||||
++fFunctorErrors;
|
||||
#ifndef NOLOGGING
|
||||
@ -320,13 +334,14 @@ void ThreadPool::beginThread() throw()
|
||||
ml.logErrorMessage( message );
|
||||
#endif
|
||||
}
|
||||
|
||||
lock1.lock();
|
||||
--fIssued;
|
||||
--waitingFunctorsSize;
|
||||
fWaitingFunctors.erase(todo);
|
||||
}
|
||||
|
||||
timeout = boost::get_system_time()+boost::posix_time::minutes(10);
|
||||
timeout = boost::get_system_time() + boost::posix_time::minutes(10);
|
||||
fThreadAvailable.notify_all();
|
||||
}
|
||||
}
|
||||
@ -385,7 +400,7 @@ void ThreadPool::beginThread() throw()
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ThreadPool::addFunctor(const Functor_T &func)
|
||||
uint64_t ThreadPool::addFunctor(const Functor_T& func)
|
||||
{
|
||||
bool bAtEnd = false;
|
||||
|
||||
@ -397,10 +412,12 @@ uint64_t ThreadPool::addFunctor(const Functor_T &func)
|
||||
poolFunction.functor = func;
|
||||
fWaitingFunctors.push_back(poolFunction);
|
||||
waitingFunctorsSize++;
|
||||
|
||||
if (bAtEnd)
|
||||
{
|
||||
--fNextFunctor;
|
||||
}
|
||||
|
||||
return fNextHandle++;
|
||||
}
|
||||
|
||||
@ -417,6 +434,7 @@ void ThreadPoolMonitor::operator()()
|
||||
ostringstream filename;
|
||||
filename << "/var/log/mariadb/columnstore/trace/ThreadPool_" << fPool->name() << ".log";
|
||||
fLog = new ofstream(filename.str().c_str());
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!fLog || !fLog->is_open())
|
||||
@ -432,6 +450,7 @@ void ThreadPoolMonitor::operator()()
|
||||
ml.logWarningMessage( message );
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a timestamp for output.
|
||||
struct tm tm;
|
||||
struct timeval tv;
|
||||
@ -440,17 +459,17 @@ void ThreadPoolMonitor::operator()()
|
||||
localtime_r(&tv.tv_sec, &tm);
|
||||
|
||||
(*fLog) << setfill('0')
|
||||
<< setw(2) << tm.tm_hour << ':'
|
||||
<< setw(2) << tm.tm_min << ':'
|
||||
<< setw(2) << tm.tm_sec
|
||||
<< '.'
|
||||
<< setw(4) << tv.tv_usec/100
|
||||
<< " Name " << fPool->fName
|
||||
<< " Active " << fPool->waitingFunctorsSize
|
||||
<< " Most " << fPool->fThreadCount
|
||||
<< " Max " << fPool->fMaxThreads
|
||||
<< " Q " << fPool->fQueueSize
|
||||
<< endl;
|
||||
<< setw(2) << tm.tm_hour << ':'
|
||||
<< setw(2) << tm.tm_min << ':'
|
||||
<< setw(2) << tm.tm_sec
|
||||
<< '.'
|
||||
<< setw(4) << tv.tv_usec / 100
|
||||
<< " Name " << fPool->fName
|
||||
<< " Active " << fPool->waitingFunctorsSize
|
||||
<< " Most " << fPool->fThreadCount
|
||||
<< " Max " << fPool->fMaxThreads
|
||||
<< " Q " << fPool->fQueueSize
|
||||
<< endl;
|
||||
|
||||
// struct timespec req = { 0, 1000 * 100 }; //100 usec
|
||||
// nanosleep(&req, 0);
|
||||
|
@ -17,11 +17,11 @@
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* Work dervied from Devguy.com's Open Source C++ thread pool implementation
|
||||
* Work dervied from Devguy.com's Open Source C++ thread pool implementation
|
||||
* released under public domain:
|
||||
* http://web.archive.org/liveweb/http://dgpctk.cvs.sourceforge.net/viewvc/dgpctk/dgc%2B%2B/include/dg/thread/threadpool.h?revision=1.22&content-type=text%2Fplain
|
||||
* http://web.archive.org/liveweb/http://dgpctk.cvs.sourceforge.net/viewvc/dgpctk/dgc%2B%2B/include/dg/thread/threadpool.h?revision=1.22&content-type=text%2Fplain
|
||||
*
|
||||
* http://web.archive.org/web/20100104101109/http://devguy.com/bb/viewtopic.php?t=460
|
||||
* http://web.archive.org/web/20100104101109/http://devguy.com/bb/viewtopic.php?t=460
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
@ -62,7 +62,7 @@ public:
|
||||
|
||||
/*********************************************
|
||||
* ctor/dtor
|
||||
*
|
||||
*
|
||||
*********************************************/
|
||||
|
||||
/** @brief ctor
|
||||
@ -74,10 +74,10 @@ public:
|
||||
* @param maxThreads the maximum number of threads in this pool. This is the maximum number
|
||||
* of simultaneuous operations that can go on.
|
||||
* @param queueSize the maximum number of work tasks in the queue. This is the maximum
|
||||
* number of jobs that can queue up in the work list before invoke() blocks.
|
||||
* If 0, then threads never block and total threads may
|
||||
* exceed maxThreads. Nothing waits. Thread count will
|
||||
* idle down to maxThreads when less work is required.
|
||||
* number of jobs that can queue up in the work list before invoke() blocks.
|
||||
* If 0, then threads never block and total threads may
|
||||
* exceed maxThreads. Nothing waits. Thread count will
|
||||
* idle down to maxThreads when less work is required.
|
||||
*/
|
||||
EXPORT explicit ThreadPool( size_t maxThreads, size_t queueSize );
|
||||
|
||||
@ -88,7 +88,7 @@ public:
|
||||
|
||||
/*********************************************
|
||||
* accessors/mutators
|
||||
*
|
||||
*
|
||||
*********************************************/
|
||||
/** @brief set the work queue size
|
||||
*
|
||||
@ -98,7 +98,10 @@ public:
|
||||
|
||||
/** @brief fet the work queue size
|
||||
*/
|
||||
inline size_t getQueueSize() const { return fQueueSize; }
|
||||
inline size_t getQueueSize() const
|
||||
{
|
||||
return fQueueSize;
|
||||
}
|
||||
|
||||
/** @brief set the maximum number of threads to be used to process
|
||||
* the work queue
|
||||
@ -109,17 +112,23 @@ public:
|
||||
|
||||
/** @brief get the maximum number of threads
|
||||
*/
|
||||
inline size_t getMaxThreads() const { return fMaxThreads; }
|
||||
inline size_t getMaxThreads() const
|
||||
{
|
||||
return fMaxThreads;
|
||||
}
|
||||
|
||||
/** @brief queue size accessor
|
||||
*
|
||||
*/
|
||||
inline uint32_t getWaiting() const { return waitingFunctorsSize; }
|
||||
inline uint32_t getWaiting() const
|
||||
{
|
||||
return waitingFunctorsSize;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************
|
||||
* operations
|
||||
*
|
||||
*
|
||||
*********************************************/
|
||||
|
||||
/** @brief invoke a functor in a separate thread managed by the pool
|
||||
@ -129,7 +138,7 @@ public:
|
||||
* queueSize tasks already waiting, invoke() will block until a slot in the
|
||||
* queue comes free.
|
||||
*/
|
||||
EXPORT uint64_t invoke(const Functor_T &threadfunc);
|
||||
EXPORT uint64_t invoke(const Functor_T& threadfunc);
|
||||
|
||||
/** @brief stop the threads
|
||||
*/
|
||||
@ -151,16 +160,31 @@ public:
|
||||
*/
|
||||
EXPORT void dump();
|
||||
|
||||
EXPORT std::string& name() {return fName;}
|
||||
EXPORT std::string& name()
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
EXPORT void setName(std::string name) {fName = name;}
|
||||
EXPORT void setName(const char* name) {fName = name;}
|
||||
EXPORT void setName(std::string name)
|
||||
{
|
||||
fName = name;
|
||||
}
|
||||
EXPORT void setName(const char* name)
|
||||
{
|
||||
fName = name;
|
||||
}
|
||||
|
||||
EXPORT bool debug() {return fDebug;}
|
||||
EXPORT bool debug()
|
||||
{
|
||||
return fDebug;
|
||||
}
|
||||
|
||||
EXPORT void setDebug(bool d) {fDebug = d;}
|
||||
EXPORT void setDebug(bool d)
|
||||
{
|
||||
fDebug = d;
|
||||
}
|
||||
|
||||
friend class ThreadPoolMonitor;
|
||||
friend class ThreadPoolMonitor;
|
||||
protected:
|
||||
|
||||
private:
|
||||
@ -177,7 +201,7 @@ private:
|
||||
|
||||
/** @brief add a functor to the list
|
||||
*/
|
||||
uint64_t addFunctor(const Functor_T &func);
|
||||
uint64_t addFunctor(const Functor_T& func);
|
||||
|
||||
/** @brief thread entry point
|
||||
*/
|
||||
@ -192,7 +216,7 @@ private:
|
||||
struct beginThreadFunc
|
||||
{
|
||||
beginThreadFunc(ThreadPool& impl)
|
||||
: fImpl(impl)
|
||||
: fImpl(impl)
|
||||
{}
|
||||
|
||||
void operator() ()
|
||||
@ -200,7 +224,7 @@ private:
|
||||
fImpl.beginThread();
|
||||
}
|
||||
|
||||
ThreadPool &fImpl;
|
||||
ThreadPool& fImpl;
|
||||
};
|
||||
|
||||
struct NoOp
|
||||
@ -226,11 +250,11 @@ private:
|
||||
bool fStop;
|
||||
long fGeneralErrors;
|
||||
long fFunctorErrors;
|
||||
uint32_t waitingFunctorsSize;
|
||||
uint64_t fNextHandle;
|
||||
uint32_t waitingFunctorsSize;
|
||||
uint64_t fNextHandle;
|
||||
|
||||
std::string fName; // Optional to add a name to the pool for debugging.
|
||||
bool fDebug;
|
||||
std::string fName; // Optional to add a name to the pool for debugging.
|
||||
bool fDebug;
|
||||
};
|
||||
|
||||
// This class, if instantiated, will continuously log details about the indicated threadpool
|
||||
@ -238,25 +262,25 @@ private:
|
||||
class ThreadPoolMonitor
|
||||
{
|
||||
public:
|
||||
ThreadPoolMonitor(ThreadPool* pool) : fPool(pool), fLog(NULL)
|
||||
{
|
||||
}
|
||||
ThreadPoolMonitor(ThreadPool* pool) : fPool(pool), fLog(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~ThreadPoolMonitor()
|
||||
{
|
||||
if (fLog)
|
||||
{
|
||||
delete fLog;
|
||||
}
|
||||
}
|
||||
~ThreadPoolMonitor()
|
||||
{
|
||||
if (fLog)
|
||||
{
|
||||
delete fLog;
|
||||
}
|
||||
}
|
||||
|
||||
void operator()();
|
||||
void operator()();
|
||||
private:
|
||||
//defaults okay
|
||||
//ThreadPoolMonitor(const ThreadPoolMonitor& rhs);
|
||||
//ThreadPoolMonitor& operator=(const ThreadPoolMonitor& rhs);
|
||||
ThreadPool* fPool;
|
||||
std::ofstream* fLog;
|
||||
//defaults okay
|
||||
//ThreadPoolMonitor(const ThreadPoolMonitor& rhs);
|
||||
//ThreadPoolMonitor& operator=(const ThreadPoolMonitor& rhs);
|
||||
ThreadPool* fPool;
|
||||
std::ofstream* fLog;
|
||||
};
|
||||
|
||||
} // namespace threadpool
|
||||
|
@ -35,96 +35,114 @@ boost::mutex mutex;
|
||||
|
||||
const string timeNow()
|
||||
{
|
||||
time_t outputTime = time(0);
|
||||
struct tm ltm;
|
||||
char buf[32]; //ctime(3) says at least 26
|
||||
size_t len = 0;
|
||||
time_t outputTime = time(0);
|
||||
struct tm ltm;
|
||||
char buf[32]; //ctime(3) says at least 26
|
||||
size_t len = 0;
|
||||
#ifdef _MSC_VER
|
||||
asctime_s(buf, 32, localtime_r(&outputTime, <m));
|
||||
asctime_s(buf, 32, localtime_r(&outputTime, <m));
|
||||
#else
|
||||
asctime_r(localtime_r(&outputTime, <m), buf);
|
||||
asctime_r(localtime_r(&outputTime, <m), buf);
|
||||
#endif
|
||||
len = strlen(buf);
|
||||
if (len > 0) --len;
|
||||
if (buf[len] == '\n') buf[len] = 0;
|
||||
return buf;
|
||||
len = strlen(buf);
|
||||
|
||||
if (len > 0) --len;
|
||||
|
||||
if (buf[len] == '\n') buf[len] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Functor class
|
||||
struct foo
|
||||
{
|
||||
int64_t fData;
|
||||
int64_t fThd;
|
||||
string start;
|
||||
bool running;
|
||||
int64_t fData;
|
||||
int64_t fThd;
|
||||
string start;
|
||||
bool running;
|
||||
|
||||
void operator ()()
|
||||
{
|
||||
start = timeNow();
|
||||
void operator ()()
|
||||
{
|
||||
start = timeNow();
|
||||
|
||||
std::cout << "foo thd = " << fThd << " start " << start << std::endl;
|
||||
for (int64_t i = 0; i < 1024*1024*(fThd+0)*128; i++)
|
||||
// simulate some work
|
||||
fData++;
|
||||
std::cout << "foo thd = " << fThd << " start " << start << std::endl;
|
||||
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "foo thd = " << fThd << " start " << start << " fin " << timeNow() << std::endl;
|
||||
}
|
||||
for (int64_t i = 0; i < 1024 * 1024 * (fThd + 0) * 128; i++)
|
||||
// simulate some work
|
||||
fData++;
|
||||
|
||||
foo(int64_t i) : fThd(i), fData(i), running(true) {start=timeNow();}
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "foo thd = " << fThd << " start " << start << " fin " << timeNow() << std::endl;
|
||||
}
|
||||
|
||||
foo(const foo& copy) : fData(copy.fData), fThd(copy.fThd), start(copy.start), running(copy.running) {std::cout << "new foo " << fThd << endl;}
|
||||
foo(int64_t i) : fThd(i), fData(i), running(true)
|
||||
{
|
||||
start = timeNow();
|
||||
}
|
||||
|
||||
~foo() {running=false;}
|
||||
foo(const foo& copy) : fData(copy.fData), fThd(copy.fThd), start(copy.start), running(copy.running)
|
||||
{
|
||||
std::cout << "new foo " << fThd << endl;
|
||||
}
|
||||
|
||||
~foo()
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main( int argc, char **argv)
|
||||
int main( int argc, char** argv)
|
||||
{
|
||||
threadpool::ThreadPool pool( 20, 10 );
|
||||
std::vector<uint64_t> hndl;
|
||||
hndl.reserve(10);
|
||||
int t1 = hndl.capacity();
|
||||
uint64_t testHndl;
|
||||
uint64_t thdhndl=999;
|
||||
int64_t thd = 1;
|
||||
boost::function0<void> foofunc;
|
||||
boost::function0<void> foofunc2;
|
||||
for (int64_t y = 0; y < 1; y++)
|
||||
{
|
||||
threadpool::ThreadPool pool( 20, 10 );
|
||||
std::vector<uint64_t> hndl;
|
||||
hndl.reserve(10);
|
||||
int t1 = hndl.capacity();
|
||||
uint64_t testHndl;
|
||||
uint64_t thdhndl = 999;
|
||||
int64_t thd = 1;
|
||||
boost::function0<void> foofunc;
|
||||
boost::function0<void> foofunc2;
|
||||
|
||||
for (int64_t y = 0; y < 1; y++)
|
||||
{
|
||||
foo bar(y);
|
||||
// foofunc = bar;
|
||||
// foofunc2 = foofunc;
|
||||
std::cout << "Done with assign" << std::endl;
|
||||
std::cout << "Done with assign" << std::endl;
|
||||
|
||||
for (int64_t i = 0; i < 1; ++i)
|
||||
{
|
||||
bar.fThd=thd++;
|
||||
thdhndl = pool.invoke(bar);
|
||||
if (y<10)
|
||||
{
|
||||
hndl.push_back(thdhndl);
|
||||
}
|
||||
if (y == 0)
|
||||
{
|
||||
testHndl = thdhndl;
|
||||
}
|
||||
bar.fThd = thd++;
|
||||
thdhndl = pool.invoke(bar);
|
||||
|
||||
if (y < 10)
|
||||
{
|
||||
hndl.push_back(thdhndl);
|
||||
}
|
||||
|
||||
if (y == 0)
|
||||
{
|
||||
testHndl = thdhndl;
|
||||
}
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
}
|
||||
// Wait until all of the queued up and in-progress work has finished
|
||||
std::cout << "Threads for join " << hndl.size() << std::endl;
|
||||
pool.dump();
|
||||
std::cout << "*** JOIN 1 ***" << std::endl;
|
||||
pool.join(testHndl);
|
||||
pool.dump();
|
||||
std::cout << "*** JOIN 10 ***" << std::endl;
|
||||
pool.join(hndl);
|
||||
pool.dump();
|
||||
std::cout << "*** WAIT ***" << std::endl;
|
||||
pool.wait();
|
||||
pool.dump();
|
||||
sleep(2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wait until all of the queued up and in-progress work has finished
|
||||
std::cout << "Threads for join " << hndl.size() << std::endl;
|
||||
pool.dump();
|
||||
std::cout << "*** JOIN 1 ***" << std::endl;
|
||||
pool.join(testHndl);
|
||||
pool.dump();
|
||||
std::cout << "*** JOIN 10 ***" << std::endl;
|
||||
pool.join(hndl);
|
||||
pool.dump();
|
||||
std::cout << "*** WAIT ***" << std::endl;
|
||||
pool.wait();
|
||||
pool.dump();
|
||||
sleep(2);
|
||||
return 0;
|
||||
}
|
||||
|
@ -35,18 +35,18 @@ namespace threadpool
|
||||
{
|
||||
|
||||
WeightedThreadPool::WeightedThreadPool()
|
||||
:fMaxThreadWeight(0), fMaxThreads( 0 ), fQueueSize( 0 )
|
||||
: fMaxThreadWeight(0), fMaxThreads( 0 ), fQueueSize( 0 )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
WeightedThreadPool::WeightedThreadPool( size_t maxThreadWeight, size_t maxThreads, size_t queueSize )
|
||||
:fMaxThreadWeight(maxThreadWeight), fMaxThreads( maxThreads ), fQueueSize( queueSize )
|
||||
: fMaxThreadWeight(maxThreadWeight), fMaxThreads( maxThreads ), fQueueSize( queueSize )
|
||||
{
|
||||
init();
|
||||
|
||||
if (fQueueSize == 0)
|
||||
fQueueSize = fMaxThreads*2;
|
||||
fQueueSize = fMaxThreads * 2;
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ WeightedThreadPool::~WeightedThreadPool() throw()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{}
|
||||
}
|
||||
|
||||
@ -67,9 +67,9 @@ void WeightedThreadPool::init()
|
||||
fThreadCount = 0;
|
||||
fGeneralErrors = 0;
|
||||
fFunctorErrors = 0;
|
||||
fWaitingFunctorsSize = 0;
|
||||
fWaitingFunctorsWeight=0;
|
||||
issued = 0;
|
||||
fWaitingFunctorsSize = 0;
|
||||
fWaitingFunctorsWeight = 0;
|
||||
issued = 0;
|
||||
fStop = false;
|
||||
// fThreadCreated = new NoOp();
|
||||
fNextFunctor = fWaitingFunctors.end();
|
||||
@ -97,7 +97,7 @@ void WeightedThreadPool::setMaxThreadWeight(size_t maxWeight)
|
||||
}
|
||||
|
||||
|
||||
void WeightedThreadPool::setThreadCreatedListener(const Functor_T &f)
|
||||
void WeightedThreadPool::setThreadCreatedListener(const Functor_T& f)
|
||||
{
|
||||
// fThreadCreated = f;
|
||||
}
|
||||
@ -120,40 +120,45 @@ void WeightedThreadPool::wait()
|
||||
|
||||
while (fWaitingFunctorsSize > 0)
|
||||
{
|
||||
//cout << "waiting ..." << endl;
|
||||
//cout << "waiting ..." << endl;
|
||||
fThreadAvailable.wait(lock1);
|
||||
//cerr << "woke!" << endl;
|
||||
//cerr << "woke!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void WeightedThreadPool::removeJobs(uint32_t id)
|
||||
{
|
||||
boost::mutex::scoped_lock lock1(fMutex);
|
||||
Container_T::iterator it;
|
||||
boost::mutex::scoped_lock lock1(fMutex);
|
||||
Container_T::iterator it;
|
||||
|
||||
it = fNextFunctor;
|
||||
while (it != fWaitingFunctors.end()) {
|
||||
if (it->id == id) {
|
||||
fWaitingFunctorsWeight -= it->functorWeight;
|
||||
fWaitingFunctorsSize--;
|
||||
if (it == fNextFunctor) {
|
||||
fWaitingFunctors.erase(fNextFunctor++);
|
||||
it = fNextFunctor;
|
||||
}
|
||||
else
|
||||
fWaitingFunctors.erase(it++);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
it = fNextFunctor;
|
||||
|
||||
while (it != fWaitingFunctors.end())
|
||||
{
|
||||
if (it->id == id)
|
||||
{
|
||||
fWaitingFunctorsWeight -= it->functorWeight;
|
||||
fWaitingFunctorsSize--;
|
||||
|
||||
if (it == fNextFunctor)
|
||||
{
|
||||
fWaitingFunctors.erase(fNextFunctor++);
|
||||
it = fNextFunctor;
|
||||
}
|
||||
else
|
||||
fWaitingFunctors.erase(it++);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void WeightedThreadPool::invoke(const Functor_T &threadfunc, uint32_t functor_weight,
|
||||
uint32_t id)
|
||||
void WeightedThreadPool::invoke(const Functor_T& threadfunc, uint32_t functor_weight,
|
||||
uint32_t id)
|
||||
{
|
||||
boost::mutex::scoped_lock lock1(fMutex);
|
||||
|
||||
for(;;)
|
||||
for (;;)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -175,11 +180,11 @@ void WeightedThreadPool::invoke(const Functor_T &threadfunc, uint32_t functor_we
|
||||
bAdded = true;
|
||||
}
|
||||
|
||||
// add a thread is necessary
|
||||
// add a thread is necessary
|
||||
if ( fThreadCount < fMaxThreads)
|
||||
{
|
||||
++fThreadCount;
|
||||
//cout << "\t++invoke() tcnt=" << fThreadCount << endl;
|
||||
//cout << "\t++invoke() tcnt=" << fThreadCount << endl;
|
||||
lock1.unlock();
|
||||
fThreads.create_thread(beginThreadFunc(*this));
|
||||
|
||||
@ -192,8 +197,9 @@ void WeightedThreadPool::invoke(const Functor_T &threadfunc, uint32_t functor_we
|
||||
lock1.lock();
|
||||
continue;
|
||||
}
|
||||
//else
|
||||
// cout << "invoke() no thread created c=" << fThreadCount << " m=" << fMaxThreads << endl;
|
||||
|
||||
//else
|
||||
// cout << "invoke() no thread created c=" << fThreadCount << " m=" << fMaxThreads << endl;
|
||||
|
||||
if (bAdded)
|
||||
{
|
||||
@ -203,7 +209,7 @@ void WeightedThreadPool::invoke(const Functor_T &threadfunc, uint32_t functor_we
|
||||
|
||||
fThreadAvailable.wait(lock1);
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
++fGeneralErrors;
|
||||
throw;
|
||||
@ -215,13 +221,14 @@ void WeightedThreadPool::invoke(const Functor_T &threadfunc, uint32_t functor_we
|
||||
|
||||
void WeightedThreadPool::beginThread() throw()
|
||||
{
|
||||
vector<bool> reschedule;
|
||||
vector<bool> reschedule;
|
||||
|
||||
try
|
||||
{
|
||||
// fThreadCreated();
|
||||
boost::mutex::scoped_lock lock1(fMutex);
|
||||
|
||||
for(;;)
|
||||
for (;;)
|
||||
{
|
||||
if (fStop)
|
||||
break;
|
||||
@ -233,78 +240,90 @@ void WeightedThreadPool::beginThread() throw()
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<Container_T::iterator> todoList;
|
||||
int i, num = (fWaitingFunctorsSize - issued);
|
||||
Container_T::const_iterator iter;
|
||||
uint32_t weight=0;
|
||||
vector<Container_T::iterator> todoList;
|
||||
int i, num = (fWaitingFunctorsSize - issued);
|
||||
Container_T::const_iterator iter;
|
||||
uint32_t weight = 0;
|
||||
|
||||
for (i = 0; i < num && weight < fMaxThreadWeight; i++) {
|
||||
weight += (*fNextFunctor).functorWeight;
|
||||
todoList.push_back(fNextFunctor++);
|
||||
}
|
||||
issued+=i;
|
||||
num=i;
|
||||
for (i = 0; i < num && weight < fMaxThreadWeight; i++)
|
||||
{
|
||||
weight += (*fNextFunctor).functorWeight;
|
||||
todoList.push_back(fNextFunctor++);
|
||||
}
|
||||
|
||||
issued += i;
|
||||
num = i;
|
||||
lock1.unlock();
|
||||
|
||||
//cerr << "beginThread() " << num
|
||||
// << " jobs - fWaitingFunctorsSize=" << fWaitingFunctorsSize
|
||||
// << " fWaitingFunctorsWeight=" << fWaitingFunctorsWeight
|
||||
// << " weight=" << weight
|
||||
// << " issued=" << issued << " todo=" << todoList.size()
|
||||
// << " fThreadCount=" << fThreadCount << endl;
|
||||
|
||||
i = 0;
|
||||
reschedule.resize(num);
|
||||
bool allWereRescheduled = true, someWereRescheduled = false;
|
||||
while (i < num) {
|
||||
try {
|
||||
for (; i < num; i++) {
|
||||
reschedule[i] = false; // in case of exception in the next line
|
||||
reschedule[i] = ((*todoList[i]).functor)();
|
||||
allWereRescheduled &= reschedule[i];
|
||||
someWereRescheduled |= reschedule[i];
|
||||
}
|
||||
}
|
||||
catch(exception &e) {
|
||||
i++;
|
||||
++fFunctorErrors;
|
||||
cerr << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// no real work was done, prevent intensive busy waiting
|
||||
if (allWereRescheduled)
|
||||
usleep(1000);
|
||||
//cerr << "beginThread() " << num
|
||||
// << " jobs - fWaitingFunctorsSize=" << fWaitingFunctorsSize
|
||||
// << " fWaitingFunctorsWeight=" << fWaitingFunctorsWeight
|
||||
// << " weight=" << weight
|
||||
// << " issued=" << issued << " todo=" << todoList.size()
|
||||
// << " fThreadCount=" << fThreadCount << endl;
|
||||
|
||||
//cout << "running " << i << "/" << num << " functor" <<endl;
|
||||
lock1.lock();
|
||||
i = 0;
|
||||
reschedule.resize(num);
|
||||
bool allWereRescheduled = true, someWereRescheduled = false;
|
||||
|
||||
if (someWereRescheduled) {
|
||||
for (i = 0; i < num; i++)
|
||||
if (reschedule[i])
|
||||
addFunctor((*todoList[i]).functor, (*todoList[i]).functorWeight,
|
||||
(*todoList[i]).id);
|
||||
if (num > 1)
|
||||
fNeedThread.notify_all();
|
||||
else
|
||||
fNeedThread.notify_one();
|
||||
}
|
||||
while (i < num)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (; i < num; i++)
|
||||
{
|
||||
reschedule[i] = false; // in case of exception in the next line
|
||||
reschedule[i] = ((*todoList[i]).functor)();
|
||||
allWereRescheduled &= reschedule[i];
|
||||
someWereRescheduled |= reschedule[i];
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
i++;
|
||||
++fFunctorErrors;
|
||||
cerr << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
issued -= num;
|
||||
for (i = 0; i < num; i++) {
|
||||
fWaitingFunctorsWeight-=(*todoList[i]).functorWeight;
|
||||
fWaitingFunctors.erase(todoList[i]);
|
||||
}
|
||||
fWaitingFunctorsSize -= num;
|
||||
// no real work was done, prevent intensive busy waiting
|
||||
if (allWereRescheduled)
|
||||
usleep(1000);
|
||||
|
||||
//if (fWaitingFunctorsSize != fWaitingFunctors.size()) ;
|
||||
// cerr << "num=" << num << " cleaned=" << i << " size="
|
||||
// << fWaitingFunctorsSize << " list size="
|
||||
// << fWaitingFunctors.size()
|
||||
// << " w="<<fWaitingFunctorsWeight << endl;
|
||||
//cout << "running " << i << "/" << num << " functor" <<endl;
|
||||
lock1.lock();
|
||||
|
||||
if (someWereRescheduled)
|
||||
{
|
||||
for (i = 0; i < num; i++)
|
||||
if (reschedule[i])
|
||||
addFunctor((*todoList[i]).functor, (*todoList[i]).functorWeight,
|
||||
(*todoList[i]).id);
|
||||
|
||||
if (num > 1)
|
||||
fNeedThread.notify_all();
|
||||
else
|
||||
fNeedThread.notify_one();
|
||||
}
|
||||
|
||||
issued -= num;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
fWaitingFunctorsWeight -= (*todoList[i]).functorWeight;
|
||||
fWaitingFunctors.erase(todoList[i]);
|
||||
}
|
||||
|
||||
fWaitingFunctorsSize -= num;
|
||||
|
||||
//if (fWaitingFunctorsSize != fWaitingFunctors.size()) ;
|
||||
// cerr << "num=" << num << " cleaned=" << i << " size="
|
||||
// << fWaitingFunctorsSize << " list size="
|
||||
// << fWaitingFunctors.size()
|
||||
// << " w="<<fWaitingFunctorsWeight << endl;
|
||||
|
||||
fThreadAvailable.notify_all();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,12 +348,12 @@ void WeightedThreadPool::beginThread() throw()
|
||||
ml.logErrorMessage( message );
|
||||
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
++fGeneralErrors;
|
||||
|
||||
@ -352,27 +371,27 @@ void WeightedThreadPool::beginThread() throw()
|
||||
|
||||
ml.logErrorMessage( message );
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WeightedThreadPool::addFunctor(const Functor_T &func, uint32_t functor_weight,
|
||||
uint32_t id)
|
||||
void WeightedThreadPool::addFunctor(const Functor_T& func, uint32_t functor_weight,
|
||||
uint32_t id)
|
||||
{
|
||||
bool bAtEnd=false;
|
||||
bool bAtEnd = false;
|
||||
|
||||
if (fNextFunctor == fWaitingFunctors.end())
|
||||
bAtEnd = true;
|
||||
|
||||
//cout << "addFunctor() w=" << fWaitingFunctorsWeight
|
||||
// << " s=" << fWaitingFunctorsSize << " i=" << id << endl;
|
||||
//cout << "addFunctor() w=" << fWaitingFunctorsWeight
|
||||
// << " s=" << fWaitingFunctorsSize << " i=" << id << endl;
|
||||
|
||||
FunctorListItem fl = {func, functor_weight, id};
|
||||
FunctorListItem fl = {func, functor_weight, id};
|
||||
fWaitingFunctors.push_back(fl);
|
||||
fWaitingFunctorsSize++;
|
||||
fWaitingFunctorsWeight+=functor_weight;
|
||||
fWaitingFunctorsSize++;
|
||||
fWaitingFunctorsWeight += functor_weight;
|
||||
|
||||
if (bAtEnd)
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
|
||||
/*********************************************
|
||||
* ctor/dtor
|
||||
*
|
||||
*
|
||||
*********************************************/
|
||||
|
||||
/** @brief ctor
|
||||
@ -74,7 +74,7 @@ public:
|
||||
|
||||
/*********************************************
|
||||
* accessors/mutators
|
||||
*
|
||||
*
|
||||
*********************************************/
|
||||
/** @brief set the work queue size
|
||||
*
|
||||
@ -84,7 +84,10 @@ public:
|
||||
|
||||
/** @brief fet the work queue size
|
||||
*/
|
||||
inline size_t getQueueSize() const { return fQueueSize; }
|
||||
inline size_t getQueueSize() const
|
||||
{
|
||||
return fQueueSize;
|
||||
}
|
||||
|
||||
/** @brief set the maximum number of threads to be used to process
|
||||
* the work queue
|
||||
@ -95,11 +98,14 @@ public:
|
||||
|
||||
/** @brief get the maximum number of threads
|
||||
*/
|
||||
inline size_t getMaxThreads() const { return fMaxThreads; }
|
||||
inline size_t getMaxThreads() const
|
||||
{
|
||||
return fMaxThreads;
|
||||
}
|
||||
|
||||
/** @brief set the maximum processing weight of a thread to be
|
||||
* submitted for execution from the existing jobs
|
||||
* scheduled in the work queue
|
||||
* scheduled in the work queue
|
||||
*
|
||||
* @param maxWeight for execution
|
||||
*/
|
||||
@ -107,25 +113,34 @@ public:
|
||||
|
||||
/** @brief get the maximum number of threads
|
||||
*/
|
||||
inline uint32_t getMaxThreadWeight() const { return fMaxThreadWeight; }
|
||||
inline uint32_t getMaxThreadWeight() const
|
||||
{
|
||||
return fMaxThreadWeight;
|
||||
}
|
||||
|
||||
/** @brief register a functor to be called when a new thread
|
||||
* is created
|
||||
*/
|
||||
void setThreadCreatedListener(const Functor_T &f) ;
|
||||
void setThreadCreatedListener(const Functor_T& f) ;
|
||||
|
||||
/** @brief queue size accessor
|
||||
*
|
||||
*/
|
||||
inline uint32_t getWaiting() const { return fWaitingFunctorsSize; }
|
||||
inline uint32_t getWaiting() const
|
||||
{
|
||||
return fWaitingFunctorsSize;
|
||||
}
|
||||
|
||||
inline uint32_t getWeight() const { return fWaitingFunctorsWeight; }
|
||||
inline uint32_t getWeight() const
|
||||
{
|
||||
return fWaitingFunctorsWeight;
|
||||
}
|
||||
|
||||
void removeJobs(uint32_t id);
|
||||
|
||||
/*********************************************
|
||||
* operations
|
||||
*
|
||||
*
|
||||
*********************************************/
|
||||
|
||||
/** @brief invoke a functor in a separate thread managed by the pool
|
||||
@ -135,7 +150,7 @@ public:
|
||||
* queueSize tasks already waiting, invoke() will block until a slot in the
|
||||
* queue comes free.
|
||||
*/
|
||||
void invoke(const Functor_T &threadfunc, uint32_t functor_weight, uint32_t id);
|
||||
void invoke(const Functor_T& threadfunc, uint32_t functor_weight, uint32_t id);
|
||||
|
||||
/** @brief stop the threads
|
||||
*/
|
||||
@ -158,7 +173,7 @@ private:
|
||||
|
||||
/** @brief add a functor to the list
|
||||
*/
|
||||
void addFunctor(const Functor_T &func, uint32_t functor_weight, uint32_t id);
|
||||
void addFunctor(const Functor_T& func, uint32_t functor_weight, uint32_t id);
|
||||
|
||||
/** @brief thread entry point
|
||||
*/
|
||||
@ -173,7 +188,7 @@ private:
|
||||
struct beginThreadFunc
|
||||
{
|
||||
beginThreadFunc(WeightedThreadPool& impl)
|
||||
: fImpl(impl)
|
||||
: fImpl(impl)
|
||||
{}
|
||||
|
||||
void operator() ()
|
||||
@ -181,14 +196,14 @@ private:
|
||||
fImpl.beginThread();
|
||||
}
|
||||
|
||||
WeightedThreadPool &fImpl;
|
||||
WeightedThreadPool& fImpl;
|
||||
};
|
||||
|
||||
struct NoOp
|
||||
{
|
||||
void operator () () const
|
||||
{}
|
||||
};
|
||||
};
|
||||
|
||||
size_t fThreadCount;
|
||||
size_t fMaxThreadWeight;
|
||||
@ -196,18 +211,19 @@ private:
|
||||
size_t fQueueSize;
|
||||
|
||||
//typedef std::list<Functor_T> Container_T;
|
||||
struct FunctorListItemStruct {
|
||||
Functor_T functor;
|
||||
uint32_t functorWeight;
|
||||
uint32_t id;
|
||||
};
|
||||
struct FunctorListItemStruct
|
||||
{
|
||||
Functor_T functor;
|
||||
uint32_t functorWeight;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
typedef FunctorListItemStruct FunctorListItem;
|
||||
typedef FunctorListItemStruct FunctorListItem;
|
||||
typedef std::list<FunctorListItem> Container_T;
|
||||
Container_T fWaitingFunctors;
|
||||
Container_T::iterator fNextFunctor;
|
||||
|
||||
uint32_t issued;
|
||||
uint32_t issued;
|
||||
boost::mutex fMutex;
|
||||
boost::condition fThreadAvailable; // triggered when a thread is available
|
||||
boost::condition fNeedThread; // triggered when a thread is needed
|
||||
@ -216,8 +232,8 @@ private:
|
||||
bool fStop;
|
||||
long fGeneralErrors;
|
||||
long fFunctorErrors;
|
||||
uint16_t fWaitingFunctorsSize;
|
||||
uint16_t fWaitingFunctorsWeight;
|
||||
uint16_t fWaitingFunctorsSize;
|
||||
uint16_t fWaitingFunctorsWeight;
|
||||
|
||||
};
|
||||
|
||||
|
@ -34,52 +34,52 @@ using namespace std;
|
||||
int thecount = 0;
|
||||
boost::mutex mutex;
|
||||
|
||||
// Functor class
|
||||
// Functor class
|
||||
struct foo
|
||||
{
|
||||
void operator ()()
|
||||
{
|
||||
for (int i = 0; i < 1024*1024*10; i++)
|
||||
// simulate some work
|
||||
fData++;
|
||||
void operator ()()
|
||||
{
|
||||
for (int i = 0; i < 1024 * 1024 * 10; i++)
|
||||
// simulate some work
|
||||
fData++;
|
||||
|
||||
//boost::mutex::scoped_lock lock(mutex);
|
||||
//std::cout << "foo count = " << ++thecount << " " << fData << std::endl;
|
||||
}
|
||||
//boost::mutex::scoped_lock lock(mutex);
|
||||
//std::cout << "foo count = " << ++thecount << " " << fData << std::endl;
|
||||
}
|
||||
|
||||
foo(int i):
|
||||
fData(i)
|
||||
foo(int i):
|
||||
fData(i)
|
||||
{}
|
||||
|
||||
foo(const foo& copy)
|
||||
: fData(copy.fData)
|
||||
{}
|
||||
foo(const foo& copy)
|
||||
: fData(copy.fData)
|
||||
{}
|
||||
|
||||
int fData;
|
||||
int fData;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main( int argc, char **argv)
|
||||
int main( int argc, char** argv)
|
||||
{
|
||||
threadpool::WeightedThreadPool pool( 100, 10, 5 );
|
||||
threadpool::WeightedThreadPool pool( 100, 10, 5 );
|
||||
|
||||
for (int y = 0; y < 10; y++)
|
||||
{
|
||||
for (int y = 0; y < 10; y++)
|
||||
{
|
||||
foo bar(y);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
pool.invoke(bar, 25);
|
||||
pool.invoke(bar, 25);
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "count = " << ++thecount << std::endl;
|
||||
|
||||
|
||||
// Wait until all of the queued up and in-progress work has finished
|
||||
pool.wait();
|
||||
pool.dump();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user