Romain Guy 5dc7fa7096 Add TaskManager API
This API can be used to run arbitrary tasks on a pool of worker
threads. The number of threads is calculated based on the number
of CPU cores available.

The API is made of 3 classes:

TaskManager
      Creates and manages the worker threads.

Task
      Describes the work to be done and the type of the output.
      A task contains a future used to wait for the worker thread
      to be done computing the result of the task.

TaskProcessor
      The processor dispatches tasks to the TaskManager and is
      responsible for performing the computation required by
      each task. A processor will only be asked to process tasks
      sent to the manager through the processor.

A typical use case:

class MyTask: Task<MyType>

class MyProcessor: TaskProcessor<MyType>

TaskManager m = new TaskManager();
MyProcessor p = new MyProcessor(m);
MyTask t = new MyTask();
p.add(t);

// Waits until the result is available
MyType result = t->getResult();

Change-Id: I1fe845ba4c49bb0e1b0627ab147f9a861c8e0749
2013-03-12 15:06:42 -07:00

119 lines
3.1 KiB
C++

/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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 <sys/sysinfo.h>
#include "Task.h"
#include "TaskProcessor.h"
#include "TaskManager.h"
namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// Manager
///////////////////////////////////////////////////////////////////////////////
TaskManager::TaskManager() {
// Get the number of available CPUs. This value does not change over time.
int cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
for (int i = 0; i < cpuCount / 2; i++) {
String8 name;
name.appendFormat("hwuiTask%d", i + 1);
mThreads.add(new WorkerThread(name));
}
}
TaskManager::~TaskManager() {
for (size_t i = 0; i < mThreads.size(); i++) {
mThreads[i]->exit();
}
}
bool TaskManager::canRunTasks() const {
return mThreads.size() > 0;
}
bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
if (mThreads.size() > 0) {
TaskWrapper wrapper(task, processor);
size_t minQueueSize = INT_MAX;
sp<WorkerThread> thread;
for (size_t i = 0; i < mThreads.size(); i++) {
if (mThreads[i]->getTaskCount() < minQueueSize) {
thread = mThreads[i];
minQueueSize = mThreads[i]->getTaskCount();
}
}
return thread->addTask(wrapper);
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// Thread
///////////////////////////////////////////////////////////////////////////////
bool TaskManager::WorkerThread::threadLoop() {
mSignal.wait();
Vector<TaskWrapper> tasks;
{
Mutex::Autolock l(mLock);
tasks = mTasks;
mTasks.clear();
}
for (size_t i = 0; i < tasks.size(); i++) {
const TaskWrapper& task = tasks.itemAt(i);
task.mProcessor->process(task.mTask);
}
return true;
}
bool TaskManager::WorkerThread::addTask(TaskWrapper task) {
if (!isRunning()) {
run(mName.string(), PRIORITY_DEFAULT);
}
Mutex::Autolock l(mLock);
ssize_t index = mTasks.add(task);
mSignal.signal();
return index >= 0;
}
size_t TaskManager::WorkerThread::getTaskCount() const {
Mutex::Autolock l(mLock);
return mTasks.size();
}
void TaskManager::WorkerThread::exit() {
{
Mutex::Autolock l(mLock);
mTasks.clear();
}
requestExit();
mSignal.signal();
}
}; // namespace uirenderer
}; // namespace android