2013-12-09 10:59:57 +00:00
|
|
|
#include "ParallelWork.h"
|
|
|
|
|
|
|
|
#include "Thread.h"
|
|
|
|
#include "System.h"
|
2014-08-18 10:17:16 +00:00
|
|
|
#include "ParallelWorker.h"
|
2013-12-09 10:59:57 +00:00
|
|
|
#include <cassert>
|
|
|
|
|
2014-08-18 10:17:16 +00:00
|
|
|
/**
|
|
|
|
* Compatibility class for code that uses ParallelUnitFunction.
|
|
|
|
*/
|
|
|
|
class ParallelWorkerCompat:public ParallelWorker
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ParallelWorkerCompat(ParallelWork *work, ParallelWork::ParallelUnitFunction func, void* data):
|
|
|
|
ParallelWorker(), work(work), func(func), data(data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int processParallelUnit(int unit)
|
|
|
|
{
|
|
|
|
return func(work, unit, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ParallelWork* work;
|
|
|
|
ParallelWork::ParallelUnitFunction func;
|
|
|
|
void* data;
|
|
|
|
};
|
|
|
|
|
|
|
|
ParallelWork::ParallelWork(ParallelWorker *worker, int units)
|
|
|
|
{
|
|
|
|
this->units = units;
|
|
|
|
this->running = 0;
|
|
|
|
this->worker = worker;
|
|
|
|
this->worker_compat = false;
|
|
|
|
}
|
|
|
|
|
2013-12-09 10:59:57 +00:00
|
|
|
ParallelWork::ParallelWork(ParallelUnitFunction func, int units, void* data)
|
|
|
|
{
|
|
|
|
this->units = units;
|
|
|
|
this->running = 0;
|
2014-08-18 10:17:16 +00:00
|
|
|
this->worker = new ParallelWorkerCompat(this, func, data);
|
|
|
|
this->worker_compat = true;
|
2013-12-09 10:59:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ParallelWork::~ParallelWork()
|
|
|
|
{
|
|
|
|
assert(not running);
|
2014-08-18 10:17:16 +00:00
|
|
|
if (worker_compat)
|
|
|
|
{
|
|
|
|
delete worker;
|
|
|
|
}
|
2013-12-09 10:59:57 +00:00
|
|
|
}
|
|
|
|
|
2014-08-18 10:17:16 +00:00
|
|
|
static void* _workerThreadCallback(ParallelWork::ParallelWorkerThread* thread)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
thread->result = thread->worker->processParallelUnit(thread->unit);
|
|
|
|
thread->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE;
|
2013-12-09 10:59:57 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-08-18 10:17:16 +00:00
|
|
|
static int _runNextWorker(ParallelWork::ParallelWorkerThread threads[], int thread_count, int unit)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
for (i = 0; i < thread_count; i++)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
ParallelWork::ParallelWorkerThread* worker = threads + i;
|
2013-12-09 10:59:57 +00:00
|
|
|
if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_VOID)
|
|
|
|
{
|
|
|
|
worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING;
|
|
|
|
worker->result = 0;
|
|
|
|
worker->unit = unit;
|
|
|
|
worker->thread = new Thread((ThreadFunction)_workerThreadCallback);
|
|
|
|
worker->thread->start(worker);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_DONE)
|
|
|
|
{
|
|
|
|
int result = worker->result;
|
|
|
|
|
|
|
|
worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING;
|
|
|
|
worker->result = 0;
|
|
|
|
worker->unit = unit;
|
|
|
|
worker->thread->join();
|
|
|
|
delete worker->thread;
|
|
|
|
worker->thread = new Thread((ThreadFunction)_workerThreadCallback);
|
|
|
|
worker->thread->start(worker);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Thread::timeSleepMs(50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 10:17:16 +00:00
|
|
|
int ParallelWork::perform(int thread_count)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
|
|
|
int i, done, result;
|
|
|
|
assert(not running);
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
2014-08-18 10:17:16 +00:00
|
|
|
if (thread_count <= 0)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
thread_count = System::getCoreCount();
|
2013-12-09 10:59:57 +00:00
|
|
|
}
|
2014-08-18 10:17:16 +00:00
|
|
|
if (thread_count > PARALLEL_MAX_THREADS)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
thread_count = PARALLEL_MAX_THREADS;
|
2013-12-09 10:59:57 +00:00
|
|
|
}
|
|
|
|
running = 1;
|
|
|
|
|
|
|
|
/* Init workers */
|
2014-08-18 10:17:16 +00:00
|
|
|
for (i = 0; i < thread_count; i++)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
threads[i].status = PARALLEL_WORKER_STATUS_VOID;
|
|
|
|
threads[i].worker = worker;
|
2013-12-09 10:59:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Perform run */
|
|
|
|
for (done = 0; done < units; done++)
|
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
if (_runNextWorker(threads, thread_count, done))
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait and clean up workers */
|
2014-08-18 10:17:16 +00:00
|
|
|
for (i = 0; i < thread_count; i++)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
if (threads[i].status != PARALLEL_WORKER_STATUS_VOID)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
2014-08-18 10:17:16 +00:00
|
|
|
threads[i].thread->join();
|
|
|
|
delete threads[i].thread;
|
|
|
|
if (threads[i].result)
|
2013-12-09 10:59:57 +00:00
|
|
|
{
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
running = 0;
|
|
|
|
return result;
|
|
|
|
}
|