Parallel Programming Frameworks: What are the building blocks?
Building Blocks of a parallel application Framework
Keywords: functors, work, task, application framework, types, Task Queue
Problem Statement:
1. Lightweight: Shall provide a lightweight application scheduler that can be programmed to explicitly control cpu-core assignment to a specific task, if so desired.
2. Object-Oriented: Shall allow user defined types and classes that can be added as tasks or jobs for parallel execution into the framework.
3. Flexible: Shall provide well known scheduling policies that handle the creation and synchronization of threads in an explicit way.
4. Simple Tasks: Shall allow the definition and execution of very simple application tasks that make up a larger problem.
Concepts useful to our Framework
The following is a brief discussion of a few concepts that can be used as the building blocks to a parallel framework.Using Functors to define a Task
Functors are fist class types similar to a class and can be used to define a specific task such as findMinimum in an array. These objects can be passed into a Work or a Task object, redefining their behaviour. These offer the simplicity of a function as well as hold state information. We can find some way to employ this versatile concept in our framework.
typedef struct _findMinimum {
_findMinimum (IData* idata) : _dataInterface(idata){
_dataSetRef = (int*) _dataInterface->getData();
};
~_findMinimum (){};
int operator()(int start, int end)
{
int min = getMinimum ();
if (min == -1){
return min;
}
// declares an iterator
int It = min + 1;
for (; It <= end; It++){
if (_dataSetRef[It] < _dataSetRef[min]){
min = It;
}
}
setMinimum (min);
return min;
}
IData *_dataInterface;
IDataOut* _dataOutInterface;
int* _dataSetRef;
} findMinimum;
Holding Tasks in a Basket - the Task Queue
A task queue becomes a central concept used as a holding basket for the application tasks that are executing in parallel. Tasks can exist in various states in the queue, ready to execute or completed.
A queue provides the ability to drop in the work object created and schedule it for execution by a particular type of thread. The assignment of the number of Worker threads and their type to do certain types of jobs is done by the scheduler that manages the Team of Threads. A queue plays a central role in this.
The queue is accessed initially by the main thread that creates the tasks and later by the worker and monitor threads. This calls for synchronizing access to the queue using a semaphore or a mutex object.
Team of Threads
A Team is a lightweight scheduler that needs to be discussed in some detail. A team of threads are created by our lightweight scheduler on behalf of the application.
The concept here is to allow the application to focus on specifying the task to execute. The Team of threads chose the task to execute from the queue depending on their workType. There are threads that are hard threads bound to CPU-cores and others that are soft threads and all of them execute the tasks in parallel.
The Team object gives us the ability to control the Thread affinity that we discussed earlier.
Notice the concept of using worker threads with different affinity and to do specific type of tasks. For example, I can chose to designate or give different responsibility to some threads such as monitoring or supervisory role. Some other threads purely go from round to round executing a functor.
Here is Part I of the series of articles on Hands-on Programming for Parallelism using Multi-Cores
Here is Part II of the series of articles on How to assign a cpu core to a Thread?
Here is Part III of the series of articles on These Thread Libraries offer Help
Here is Part IV of the series of articles on Building Blocks of a Parallel Framwork
Here is Part V of the series of articles on Rampaging Threads - Erecting an Effective Barrier

