Showing posts with label practical-otl. Show all posts
Showing posts with label practical-otl. Show all posts

Friday, October 16, 2015

Updating a Progress Bar From a Parallel For Loop (Plus Two Bonuses)

During the Q&A part of my Simplify Parallel Programming with Patterns presentation on CodeRage X, I’ve promised the listeners to publish a demo for updating a progress bar from a parallel for loop.

In this article I’ll try to explain few different approaches that all solve this problem. I’ve also put together a demo project which demonstrates all techniques.

Saturday, July 04, 2015

Using OmniThreadLibrary’s Message Queue with a TThread Worker

A reader recently asked about using OmniThreadLibrary’s communication channels with a TThread-based worker thread so I prepared a simple example, now part of the OTL repository (stored in the folder examples\TThread communication).
Two separate topics are covered in this example:
  • Sending data from any thread (main or background) to a TThread-based worker.
  • Sending data from a TThread-based worker to a form.

Thursday, July 10, 2014

Incrementing Progress Bar from a ForEach Loop

A deceptively simple question – how do you update a progress bar from a ForEach loop – popped up on the Google+ OmniThreadLibrary community. The implementation turned out to be quite tricky so I created an example (55_ForEachProgress) which is now part of the OmniThreadLibrary SVN repository.

The starting point was a simple Parallel.ForEach loop which I further simplified in the demo.

  Parallel
.ForEach(1,
CNumLoop)
.Execute(
procedure (const task: IOmniTask; const i:
integer)
begin
// do some work
Sleep(1
);

// update the progress bar - how?
end
);

We cannot simply update the progress bar from the ForEach executor as that code executes in a background thread and one must never ever access VCL GUI from a background thread! It is also no good to send “please update” Windows messages to main thread as Parallel.ForEach is by default blocking – it waits for all workers to stop working – and messages won’t be processed during ForEach execution.


Tuesday, October 23, 2012

Generating Reports with Background Worker

Long time ago, in August, JimVern asked on the OmniThreadLibrary forum:

I am creating a Windows Service to handle report requests for our clients.  Each client has multiple users who may run a report.  I want to serialize the report requests for one client so that only one report will run for a client at a time (FIFO), but reports can run simultaneously for different clients.

Since users can submit report requests anytime, I need to be able to append a new request to the end of an existing client FIFO queue without interrupting the execution of the current report.  Or, if the client doesn't have a queue yet (e.g., it's the first report request), then I need to be able to add a client queue without disrupting any reports running for other clients.  Once a client queue is empty, I want to destroy the client queue.

I am new to OTL, but it looks like it will easily do what I need. I'm just not sure where to focus my attention. Is there a way to create named task groups that can execute the top task of each group simultaneously, where tasks can be appended to an existing group, and where groups can auto-terminate when the tasks are all executed? Perhaps there an example project or a similar post that I can look at to get started? I'm still somewhat of a novice when it comes to threads, so any advise is also welcome.

My answer at that time was just a pointer in the correct direction:

Instead of running multiple tasks for one client, why don't you consider running one task per client and sending workload requests to that task?

You could then schedule each such task into a thread pool. The task would run in a loop and process requests. When it runs out of requests, it would shut down. The main program would be responsible for starting a new task if not already running. [There's a small race condition here - you would have to maintain a shared structure enumerating live tasks that would be modified from the task code and from the main program and it would have to be locked-accessed.]

I promised Jim a working solution but then I got lost in all sorts of other, more important projects and it was only few days ago that I was able to finish the job. Sorry, Jim :(

An example project is available in the OmniThreadLibrary repository in folder examples/report generator. This post describes the inner workings of that project.

Tuesday, July 31, 2012

Async/Await in Delphi

Let’s assume you’ve inherited this pretty useless code.
procedure TForm125.Button1Click(Sender: TObject);
var
  button: TButton;
begin
  button := Sender as TButton;
  button.Caption := 'Working ...';
  button.Enabled := false;
  Sleep(5000);
  button.Enabled := true;
  button.Caption := 'Done!';
end;

Now, your boss says, you have to make it parallel so the user can start three copies of it. (You also have to add two new buttons to the form to start those instances but that’s easy to do.)

Tuesday, January 17, 2012

OmniThreadLibrary in Practice [2a]–Backround Worker and List Partitioning

Today I’m revisiting example from November 2011. This time I’ll solve it using the new Parallel.BackgroundWorker abstraction.

Part of the Zarko’s requirements (see the original post for full text) was a cancellation support.

At any time the "master" thread could be signaled to terminate (from the app's main thread) all child threads (and itself).

When I was originally implementing this using the Parallel.Pipeline abstraction I had to put some work into the cancellation support. The main reason for this was inappropriate abstraction – Parallel.Pipeline is designed around the data flow processing and supports only a basic cancellation of the “stop everything” type. To be fair, that would comply with the Zarko’s requirements, but I wanted nicer solution where you can stop processing and then continue with a new work item without rebuilding the background thread mechanism. [Pipeline solution inherently supports cancellation but you cannot recover from it – to continue processing one would have to destroy the pipeline and build a new one.]

Thursday, November 03, 2011

OmniThreadLibrary in Practice [2]–Background Worker and List Partitioning

Today’s question was asked by Žarko Gajić, the excellent maintainer of About.com’s Delphi section.
Here's my (simplified) task I would like to solve using OTL (Delphi XE) - my real-world task is somehow more complicated but can be described as:
input: a string. output: a TStringList containing characters (one per entry) of the input string.
Example: input: "delphi"
A background thread ("master") grabs the input string and splits it into several pieces (let's say 2): "del" and "phi". For each of the split strings a new thread ("child") is created that fills in the TStringList (output) with characters from the section of the string it receives.
At any time the "master" thread could be signaled to terminate (from the app's main thread) all child threads (and itself).
When everything is done the app's main thread processes the string list.
Preferably, the order of the characters should (when all ends) be 'd', 'e', 'l', 'p', 'h', 'i' (note that characters are actually items in the resulting string list).

Thursday, October 20, 2011

OmniThreadLibrary in Practice [1]–Web Download and Database Storage

From time to time I get a question on the OmniThreadLibrary forum that could be of interest to other OmniThreadLibrary users. As I believe that many of you don’t follow that forum I have decided to repost such questions on the blog (and provide answers, of course).

The first question in this series was asked by GoustiFruit:

I need to download a list of web pages, extract data on them and then store these data in a SQLite database. The downloading/extracting part will happen in multiple threads (I'm using Synapse), but querying the database needs to be done asynchronously as I can only have one concurrent access to it.
So I'd like to know how (conceptually) I could implement that ? My first idea is to run one single thread for querying the DB, run several threads for each Url to download/analyse and then exchange messages between these threads and the querying thread, with the extracted data as a parameter: does it make sense or am I totally wrong? I also read things about the connection pool concept but I'm not sure if it applies when only one connection is allowed at one time?

Monday, September 12, 2011

Life after 2.1: Parallel data production [Introducing Parallel.Task]

An interesting problem appeared on StackOverflow shortly ago – how to generate large quantities of data as fast as possible and store it in a file. (As one could expect) I wrote a parallel solution using OmniThreadLibrary, more specifically the Parallel.ForEach high-level primitive. I’m not posting the complete solution here, just the important part – a method that accepts two parameters, requested file size and output stream, and generates the data. Actual initialization of data buffers is delegated to the FillBuffer method which you can see in the StackOverflow post.