Tutorial: Using Tasks from the Parallel Programming Library
Go Up to Parallel Programming Library Tutorials
Contents
This tutorial shows how to implement an application using tasks from the Parallel Programming Library (PPL). Tasks are units of work that are in a queue and start when the CPU time is available. Tasks can run operations in parallel. There is a master thread that manages this queue and allocates threads from the thread-pool to do work of the tasks. This thread-pool has a number of threads that depends on the number of CPUs that are available.
Creating the Project
Create a new project:
- For Delphi, choose File > New > Multi-Device Application - Delphi > Blank Application.
- For C++Builder, choose File > New > Multi-Device Application - C++Builder > Blank Application.
Adding the Components
- Add a TButton and a TLabel component to the form. TButton will start a task and TLabel will show the results.
- Drop a TScrollBar component to the form.
- Set the Align property of the scrollbar to
Top
in the Object Inspector.
- Set the Align property of the scrollbar to
- Drop a TFloatAnimation to the form.
- Nest the TFloatAnimation underneath the scrollbar. The structure of components should look like this:
- Set the AutoReverse property to
True
. - Set the Duration property to
1
second. - Set the Enabled property to
True
. - Set the Loop property to
True
. - Set the PropertyName property to
Value
. - Set the StartValue property to
0
and the StopValue to100
.
Implementing the Event Handlers for the Components
First, implement the event handler for the OnClick event of the TButton. For this, write code as follows:
Delphi:
procedure TForm1.Button1Click(Sender: TObject);
var
lValue: Integer;
begin
Label1.Text := '--';
{Some calculation that takes time}
Sleep(3000);
lValue := Random(10);
Label1.Text := lValue.ToString;
end;
end.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int lValue;
Label1->Text = "--";
//{Some calculation that takes time}
Sleep(3000);
lValue = Random(10);
Label1->Text = String(lValue);
}
This code is an example of a long calculation process that starts when you press the button. It sleeps during 3 seconds and then shows a random number between 0 and 10.
Running the Application without PPL Implementation
At this point, you can run the application:
- Press
F9
or choose Run > Run.
You will see the scrollBar moving from left to right. But as soon as you press the button and the long calculation starts, you will notice that the scrollBar stops until the calculation finishes. Obviously, this is not the expected behavior. For that reason, the next section shows how to improve this using the TTask functionality of the PPL.
Implementing the TTask Functionality
This section shows how to embed the long calculation (implemented as the OnClick event) into a TTask so that this process can run in parallel.
First, using the previous application form, rename the TButton and TLabel components as ButtonTask1 and LabelTask1, respectively.
Then, include the PPL library in the project:
uses
System.Threading;
#include <System.Threading.hpp>
To run the calculation process as a task, the PPL provides the TTask.Run method. To do this, modify and write the code as follows:
Delphi:
procedure TForm1.ButtonTask1Click(Sender: TObject);
var
lValue: Integer;
begin
Label1.Text := '--';
TTask.Run(procedure
begin
{Some calculation that takes time}
Sleep(3000);
lValue := Random(10);
TThread.Synchronize(nil,
procedure
begin
Label1.Text := lValue.ToString;
end);
end);
end;
Among the possible input parameters options that the TTask.Run method has in Delphi, the code above uses an anonymous method to do the long calculation.
Include also the code for the TCppSync
and TCppTask
classes:
class TCppSync : public TCppInterfacedObject<TThreadProcedure> {
int &lValue;
TLabel *Label;
public:
TCppSync(int &l, TLabel *lbl):lValue(l),Label(lbl)
{}
void __fastcall Invoke(){
Label->Text = String(lValue);
}
};
class TCppTask : public TCppInterfacedObject<TProc> {
int &lValue;
TLabel *Label;
public:
TCppTask(int &l, TLabel *lbl): lValue(l), Label(lbl)
{}
void __fastcall Invoke(){
Sleep(3000);
lValue = Random(10);
TThread::Synchronize(0,_di_TThreadProcedure(new TCppSync(lValue, Label)));
}
};
void __fastcall TForm1::ButtonTask1Click(TObject *Sender)
{
LabelTask1->Text = "--";
TTask::Run(_di_TProc(new TCppTask(lValue, LabelTask1)));
}
Add the declaration of lValue
in the private section of the header file:
private: // User declarations
int lValue;
Among the possible input parameters options that the TTask.Run method has in C++, the code above uses a TProc type to do the long calculation.
Running the TTask Functionality Implementation
At this point, you can now run the application:
- Press
F9
or choose Run > Run.
In this case, when you press the ButtonTask1 you will see that the scrollBar action remains active and not interrupted. So, using the TTask functionality of the PPL you can have several tasks running in parallel.