Category Archives: Advanced

Articles covering advanced topic areas

TTask.IFuture from the Parallel Programming Library

In my last post I spoke about TTask and how it enables us developers to quickly run multiple tasks at the same time with limited bottleneck in our applications. Moving on from that I want to explore IFuture which impletements ITask.

IFuture

IFuture , provides TTask with a structure us developers can use to creating a function that returns a specific type (defined using Generics, thats the <T> bit you see in code sometimes).  Using an instance of IFuture, the process can run and then allow us to get other stuff done, until such point as we need the result. This allows us to prioritise code blocks to run in the order we want them to, but still ensure we get the value we need at the point we need it!

Example

To get a value in the future, you first need to define what type of value, set it running and then go call it. To view this, below I am using a totally pointless (but shows how to use this feature) block of code, which I will break down step by step afterwards.

procedure TFormThreading.Button3Click(Sender: TObject);
var
 OneValue: IFuture <Integer>;
 OtherValue: Integer;
 Total: Integer;
begin
 OneValue := TTask.Future<Integer>(function: Integer
   begin
     Result := ComputeSomething;
     Sleep(1000); // delay to show status
   end);

 Memo1.Lines.Add(TRttiEnumerationType.
 GetName<TTaskStatus>(OneValue.Status));

 OtherValue := ComputeSomething;

 Memo1.Lines.Add(TRttiEnumerationType.
 GetName<TTaskStatus>(OneValue.Status));

 Total := OtherValue + OneValue.Value;

 Memo1.Lines.Add(TRttiEnumerationType.
 GetName<TTaskStatus>(OneValue.Status));

 // result
 Memo1.Lines.Add(Total.ToString);
end;

The output of this code looks something like this..

IFutures

Key points in the code

The first step, is using TTask.Future<T> to define the type to be returned, and then pass in the anonymous method to return the instance of that value. (Here we are getting an Integer from ComputeSomething so we use Integer as the type)

The output of calling TTask.Future is an instance of IFuture into the OneValue variable defined.

 OneValue := TTask.Future<Integer>(function: Integer
   begin
     Result := ComputeSomething;
     Sleep(1000); // delay to show status
   end);

OK, so putting a Sleep command in the anonymous method here is kind of pointless, but it does allow when running this demo code to see the result of the call to OneValue.Status change from WaitingToRun, to Running, to Completed.

As you read down further, you will see OneValue being queried for its current status. The code for converting our Future’s Status to a string is the same as any other Enumeration type, pass in the type you want to convert and the value to GetName.

TRttiEnumerationType.
 GetName<TTaskStatus>(OneValue.Status)

The first value returned will be WaitingToRun as everything is prepared. Following the first status query, we call the same ComputeSomething task

 OtherValue := ComputeSomething;

Afterwards, we can check the status of OneValue and see that (due to the sleep taking longer than the ComputeSomething call) its now reporting as running.

So hold on! Does that mean we need to check the status to see if its OK to get the value? Well actually NO 🙂

 Total := OtherValue + OneValue.Value;

This line asks OneValue for its Value. If it is done, it will have the value ready for you, if not (as in this case) it will block and wait for IFuture to finish before executing the code making life very easy on us developers.

So thats IFuture, its a process that you can set running, but will return at the point it is ready. Another way to save time and speed up your application code.

Using TTask from the Parallel programming library

In my last post on using Parallel Programming and the TParallel.For construct we learned about the new System.Threading unit and how to use TParallel to make looping faster.  There are however times when you need to run multiple tasks that are not loops, but these can run in parallel.

Running a number of processes in tandem has been greatly simplified with System.Threading.TTask and System.Threading.ITask

TTask provides a class to create & manage interaction with instances of ITask. You can choose to WaitForAll or WaitForAny to finish before proceeding in code.

To give an example. Imagine you have two tasks. A and B.
If A takes 3 seconds and B takes 5 seconds how long does it take to get a result to a user?

  • Sequentially (without TTask / ITask) = 8 seconds.
  • Using TTask.WaitForAll = 5 seconds
  • Using TTask.WaitForAny = 3 seconds

Depending on what your doing, the speed for return can be dramatically quicker. So lets look at a code example for WaitForAll.

procedure TFormThreading.MyButtonClick(Sender: TObject);
var
 tasks: array of ITask;
 value: Integer;
begin
 Setlength (tasks ,2);
 value := 0;

 tasks[0] := TTask.Create (procedure ()
   begin
     sleep (3000); // 3 seconds
     TInterlocked.Add (value, 3000);
   end);
 tasks[0].Start;

 tasks[1] := TTask.Create (procedure ()
   begin
     sleep (5000); // 5 seconds
     TInterlocked.Add (value, 5000);
   end);
 tasks[1].Start;

 TTask.WaitForAll(tasks);
 ShowMessage ('All done: ' + value.ToString);
end

The above example uses an Array of ITask to process a set of tasks. The result returned is 8000, but despite 8 seconds worth of sleep commands, the first 3 seconds run in parallel, leaving the second task to finish before returning 2 seconds later, which equates to a 3 second gain on sequentially running the two tasks; and all of this without having to create your own custom threads and managing them return. 🙂

While speeding up a task to run before returning is good, you can also use TTask to prevent the user interface locking up if you want to start something in the background.  To do this, you can just run a single task and start it, for example

procedure TFormThreading.Button1Click(Sender: TObject);
var
 aTask: ITask;
begin
 // not a thread safe snippet
 aTask := TTask.Create (procedure ()
   begin
     sleep (3000); // 3 seconds
     ShowMessage ('Hello');
   end);
 aTask.Start;
end;

This second example, if used, would allow the user to press the button multiple times resulting in multiple ShowMessage calls, however, used with care this is a powerful way to run task. This is also an example of asynchronous programming where you can start the Task, get on with other stuff, and then deal with the result as it returns.

ITask

ITasks provide a range of methods and properties to Start, Wait, Cancel and also a property for Status (Created, WaitingToRun, Running, Completed, WaitingForChildren, Canceled, Exception)

As ITask is an interface, you can always create your own classes that use ITask if you so wish, providing great flexibility to the frame work.

Calling JNI and Java API’s with Delphi and Appmethod

Following on from the iOS specific session that spoke about iOS and talking to Objective C API’s, Jim McKeeth has done a session on Java and the JNI (Java Native Interface) bridge to the Java API’s.

He speaks about conditional defines and how to use JNI to speak to a custom set of Java Libraries. While mainly in Object Pascal, the same technique is used to access via C++ and demos are done in both language.

The video covers the creation of class methods and regular methods that are then used with the TJavaGenericImport class to bring them all together ready for importing. (A walk through is also provided on DocWiki)

http://docwiki.embarcadero.com/RADStudio/XE6/en/Using_a_Custom_Set_of_Java_Libraries_In_Your_RAD_Studio_Android_Apps

The example in the video covers a string being Base64 encoded using a JNI call. For the steps to create the custom classes.dex file  you can also see Jim’s blog post at http://delphi.org/2014/07/custom-classes-dex/

Calling Objective C API’s with Delphi and Appmethod

Jacob Thurman from TwoDesk Software did a great developer skill sprint session on “Integrating more iOS with an Objective-C Call in your Delphi App” last week. If you have not been on them, the developer skill sprints series are excellent 20 minute deep dives into specific technologies in RAD Studio and Appmethod using both Delphi programming and C++ programming language.

What I like about this video is that it assumes no knowledge of Objective C and explains excellently the difference between Delphi, C++ and Objective C.