Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
libdeng2: Added concurrent tasks (Task and TaskPool)
  • Loading branch information
skyjake committed May 2, 2013
1 parent 05bc4e7 commit 1013bbc
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 3 deletions.
12 changes: 9 additions & 3 deletions doomsday/libdeng2/concurrency.pri
Expand Up @@ -2,16 +2,22 @@ HEADERS += \
include/de/Guard \
include/de/Lockable \
include/de/ReadWriteLockable \
include/de/Waitable
include/de/Task \
include/de/TaskPool \
include/de/Waitable

HEADERS += \
include/de/concurrency/guard.h \
include/de/concurrency/lockable.h \
include/de/concurrency/readwritelockable.h \
include/de/concurrency/waitable.h
include/de/concurrency/task.h \
include/de/concurrency/taskpool.h \
include/de/concurrency/waitable.h

SOURCES += \
src/concurrency/guard.cpp \
src/concurrency/lockable.cpp \
src/concurrency/readwritelockable.cpp \
src/concurrency/waitable.cpp
src/concurrency/task.cpp \
src/concurrency/taskpool.cpp \
src/concurrency/waitable.cpp
1 change: 1 addition & 0 deletions doomsday/libdeng2/include/de/Task
@@ -0,0 +1 @@
#include "concurrency/task.h"
1 change: 1 addition & 0 deletions doomsday/libdeng2/include/de/TaskPool
@@ -0,0 +1 @@
#include "concurrency/taskpool.h"
56 changes: 56 additions & 0 deletions doomsday/libdeng2/include/de/concurrency/task.h
@@ -0,0 +1,56 @@
/** @file task.h Concurrent task.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_TASK_H
#define LIBDENG2_TASK_H

#include <QRunnable>

#include "../libdeng2.h"

namespace de {

class TaskPool;

/**
* Concurrent task that will be executed by a TaskPool asynchronously. Override
* runTask() in a derived class.
*/
class DENG2_PUBLIC Task : public QRunnable
{
public:
Task();
virtual ~Task() {}

TaskPool &pool() const;
void run();

/**
* Task classes must override this.
*/
virtual void runTask() = 0;

private:
friend class TaskPool;

TaskPool *_pool;
};

} // namespace de

#endif // LIBDENG2_TASK_H
80 changes: 80 additions & 0 deletions doomsday/libdeng2/include/de/concurrency/taskpool.h
@@ -0,0 +1,80 @@
/** @file taskpool.h Pool of tasks.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_TASKPOOL_H
#define LIBDENG2_TASKPOOL_H

#include <QObject>

#include "../libdeng2.h"

namespace de {

class Task;

/**
* Pool of concurrent tasks.
*/
class DENG2_PUBLIC TaskPool : public QObject
{
Q_OBJECT

public:
enum Priority
{
LowPriority = 0,
MediumPriority = 1,
HighPriority = 2
};

public:
TaskPool();

virtual ~TaskPool();

/**
* Starts a new concurrent task. Ownership of the task is given to the
* pool.
*
* @param task Task instance. Ownership given.
*/
void start(Task *task, Priority priority = LowPriority);

/**
* Blocks execution until all running tasks have finished.
*/
void waitForDone();

/**
* Determines if all started tasks have finished.
*/
bool isDone() const;

signals:
void allTasksDone();

private:
friend class Task;
void taskFinished(Task &task);

DENG2_PRIVATE(d)
};

} // namespace de

#endif // LIBDENG2_TASKPOOL_H
43 changes: 43 additions & 0 deletions doomsday/libdeng2/src/concurrency/task.cpp
@@ -0,0 +1,43 @@
/** @file task.cpp Concurrent task.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#include "de/Task"
#include "de/TaskPool"
#include "de/Log"

namespace de {

Task::Task() : _pool(0)
{}

TaskPool &Task::pool() const
{
DENG2_ASSERT(_pool != 0);
return *_pool;
}

void Task::run()
{
runTask();

// Cleanup.
pool().taskFinished(*this);
Log::disposeThreadLog();
}

} // namespace de
110 changes: 110 additions & 0 deletions doomsday/libdeng2/src/concurrency/taskpool.cpp
@@ -0,0 +1,110 @@
/** @file taskpool.cpp
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#include "de/TaskPool"
#include "de/Task"
#include "de/Guard"

#include <QThreadPool>
#include <de/Lockable>
#include <de/Waitable>

namespace de {

DENG2_PIMPL(TaskPool), public Lockable, public Waitable
{
// Set of running tasks.
typedef QSet<Task *> Tasks;
Tasks tasks;

Instance(Public *i) : Base(i)
{
// When empty, the semaphore is available.
post();
}

~Instance()
{
waitForEmpty();
}

void add(Task *t)
{
DENG2_GUARD(this);
t->_pool = &self;
if(tasks.isEmpty())
{
wait(); // Semaphore now unavailable.
}
tasks.insert(t);
}

void remove(Task *t)
{
DENG2_GUARD(this);
tasks.remove(t);
if(tasks.isEmpty())
{
post();
}
}

void waitForEmpty() const
{
wait();
DENG2_GUARD(this);
DENG2_ASSERT(tasks.isEmpty());
post();
}

bool isEmpty() const
{
DENG2_GUARD(this);
return tasks.isEmpty();
}
};

TaskPool::TaskPool() : d(new Instance(this))
{}

TaskPool::~TaskPool()
{}

void TaskPool::start(Task *task, Priority priority)
{
d->add(task);
QThreadPool::globalInstance()->start(task, int(priority));
}

void TaskPool::waitForDone()
{
d->waitForEmpty();
}

void TaskPool::taskFinished(Task &task)
{
d->remove(&task);

if(d->isEmpty())
{
allTasksDone();
}
}

} // namespace de

0 comments on commit 1013bbc

Please sign in to comment.