Tutorial: Using Tasks from the Parallel Programming Library

From RAD Studio
Jump to: navigation, search

Go Up to Parallel Programming Library Tutorials

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

  1. Add a TButton and a TLabel component to the form. TButton will start a task and TLabel will show the results.
  2. Drop a TScrollBar component to the form.
  3. Drop a TFloatAnimation to the form.
    • Nest the TFloatAnimation underneath the scrollbar. The structure of components should look like this:
    Structure task.png

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.
C++:
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.
Run1.png

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:

For Delphi applications, add the following unit to the uses clause, if it's not present:
uses
  System.Threading;
For C++ applications, add the following include operator to the project header file:
#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.

C++:

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.

See Also