paysages3d/src/system/ParallelWork.cpp

150 lines
3.6 KiB
C++
Raw Normal View History

#include "ParallelWork.h"
#include "Thread.h"
#include "System.h"
2014-08-18 10:17:16 +00:00
#include "ParallelWorker.h"
#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;
}
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;
}
ParallelWork::~ParallelWork()
{
assert(not running);
2014-08-18 10:17:16 +00:00
if (worker_compat)
{
delete worker;
}
}
2014-08-18 10:17:16 +00:00
static void* _workerThreadCallback(ParallelWork::ParallelWorkerThread* thread)
{
2014-08-18 10:17:16 +00:00
thread->result = thread->worker->processParallelUnit(thread->unit);
thread->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE;
return NULL;
}
2014-08-18 10:17:16 +00:00
static int _runNextWorker(ParallelWork::ParallelWorkerThread threads[], int thread_count, int unit)
{
int i;
while (1)
{
2014-08-18 10:17:16 +00:00
for (i = 0; i < thread_count; i++)
{
2014-08-18 10:17:16 +00:00
ParallelWork::ParallelWorkerThread* worker = threads + i;
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)
{
int i, done, result;
assert(not running);
result = 0;
2014-08-18 10:17:16 +00:00
if (thread_count <= 0)
{
2014-08-18 10:17:16 +00:00
thread_count = System::getCoreCount();
}
2014-08-18 10:17:16 +00:00
if (thread_count > PARALLEL_MAX_THREADS)
{
2014-08-18 10:17:16 +00:00
thread_count = PARALLEL_MAX_THREADS;
}
running = 1;
/* Init workers */
2014-08-18 10:17:16 +00:00
for (i = 0; i < thread_count; i++)
{
2014-08-18 10:17:16 +00:00
threads[i].status = PARALLEL_WORKER_STATUS_VOID;
threads[i].worker = worker;
}
/* Perform run */
for (done = 0; done < units; done++)
{
2014-08-18 10:17:16 +00:00
if (_runNextWorker(threads, thread_count, done))
{
result++;
}
}
/* Wait and clean up workers */
2014-08-18 10:17:16 +00:00
for (i = 0; i < thread_count; i++)
{
2014-08-18 10:17:16 +00:00
if (threads[i].status != PARALLEL_WORKER_STATUS_VOID)
{
2014-08-18 10:17:16 +00:00
threads[i].thread->join();
delete threads[i].thread;
if (threads[i].result)
{
result++;
}
}
}
running = 0;
return result;
}