Wednesday, November 09, 2011

TOmniValue handles arrays, hashes and records

Arrays

For quite some time, TOmniValue record has the ability to store arrays. You would use

TOmniValue.Create([1, 2, OTL, TButton.Create(nil)]) 
and some magic would store this array inside TOmniValue.
The problem, though, was that this magic was quite lame. The array was converted to a ‘variant array’ and you could only access its elements as Variant type. This, besides other things, meant that it was not simple to store pointers, interfaces and objects in TOmniValue array. Or, better said, it was simple to store them but not simple to retrieve them. You needed some ugly casting like

o := TButton(NativeUInt(ov[1]));
Since today, TOmniValue supports native arrays, that is, each item in the array is again of the TOmniValue type.

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).

Saturday, October 29, 2011

ITDevCon 2011–recap

ITDevCon 2011 has closed its doors and I’m back at home, completely washed out. It was tiresome but it was also fun!

All the sessions I’ve visited were interesting and I always managed to learn something new. If I would have to expose three most important products I didn’t knew before, I would mention (in the order I learned about them) CopyCat, a great database replication engine which you can compile into your application; Delphi Relax, an extension to Delphi’s WebBroker and DataSnap REST architecture; and DORM, a new ORM for Delphi.

Thursday, October 27, 2011

ITDevCon 2011

Just few photos from the opening session …

P1070456P1070458P1070462P1070463P1070464P1070465P1070470

Wednesday, October 26, 2011

Nasty COM regression in XE2

David Heffernan found a nasty RTL bug in XE2 COM implementation.

Is COM broken in XE2, and how might I work around it?

I’ve found a workaround (see the link above), but it is ugly and this should really be fixed in the next XE2 update so please – vote on the QC #100414!

Update: XE2 Update 2 fixes the bug described above. Great response time from Embarcadero!

Saturday, October 22, 2011

Multithreading Made Simple–additional material

Thank you for listening to my CodeRage 6 presentation! I’m very sorry that there were some issues with the sound that were caused by network problems :( If you want to look at the presentation again (or for the first time), please go to the Embarcadero CodeCentral or download the presentation from my Dropbox.

To help you understanding the complicated world of multithreading I’ve repacked the complete presentation in a longish PDF with slides and a transcript of my talk. (Actually, it was done vice versa – first I wrote that script and only then I prepared the presentation based on the script.) You can also download the code that was used for the presentation.

If you have any questions or if you asked me something after the presentation and I didn’t understand your question and answered something completely unrelated or even if my answer was too short and you want to learn more - feel free to leave a comment here or open a new topic in the forum.

Friday, October 21, 2011

Multithreading Made Simple

Keep in mind – my session on high-level OmniThreadLibrary stuff goes on air at 06:00 AM PDT / 15:00 CET.

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?

Sunday, October 16, 2011

CodeRage 6 is Starting!

Tomorrow starts the CodeRage week!

My presentation is scheduled for Friday, 21st, at 06:00 PDT / 15:00 CET, which is early for the West coast folks but great for East cost and us Europeans. See you there!

Tuesday, October 11, 2011

OmniThreadLibrary 2.2

Only three months since 2.1 and a new release is already here? What’s going on?

I had to change some things to make OTL work in XE2 and although I could simply release new files as a patch I noticed that I’ve also done quite some work on exception handling and that I could equally well wrap everything in a new release.

Here it is: ZIP, SVN, UML diagrams (provided by Rich Shealer; Rich, thanks!).

Friday, October 07, 2011

Hear Me at CodeRage

CodeRage 6 will start in ten days! Will you be there? I’ll be joining it for the sixth time as a listener and for the first time as presenter!
The exact date and time of the presentation was not determined yet (if you look at the session list you’ll see some empty spots – I’m one of them). I’ll let you know when the timeslot is fixed. In the meantime, go and register for the conference!
The topic of my talk you can probably guess – multithreading with the OmniThreadLibrary. Due to a limited session time and to attract as wide an audience as possible, I’ve decided to focus on high-level OTL functionality. The title of the talk is Multithreading made simple and it will deal with Async, Future, ForEach, Pipeline, ForkJoin, Join, and ParallelTask.

Wednesday, September 28, 2011

NeverSleepOnThreadContention–NOT!

FastMM is a wonderful memory manager, but it can slow down quite a lot when used in multithreading environment. While Pierre has implemented some conditional defines that could help the multithreaded code, namely NeverSleepOnThreadContention and SwitchToThread, I’m now making a point that you shouldn’t ever use them! Just see for yourself.

Friday, September 16, 2011

Meet Me in Verona

SpeakerButtonI know that XE2 on Win64, OS/X and iOS is all the rage but some of us (or is it most of us?) still have to make living in the Win32 world. That’s why my ITDevCon 2011 talks are not focused into specific technologies but into techniques and tools that will make your life easier. (At least your life as a programmer, that is.)

If you have time and you live close enough, come to Verona at the end of October and meet many interesting people. Lots of speakers, three separate tracks, free lunch and wifi – what do you want more? David I is rumored to be there, Marco Cantù will lead sessions all the time and you’ll have a chance to talk to me. I’ll be giving four sessions, some targeted at beginners, some at experienced programmers. (All between those extremes are also invited, of course.)

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.

Tuesday, September 06, 2011

Life after 2.1: Pimp My Pipeline

While the biggest focus on the Pipeline improvement was on the exception handling, there were also some changes in the basic functionality.

The most important (and code breaking!) change happened to the Input function, which was renamed to From. If you now want to pass a input queue to a pipeline, use pipeline.From(queue).

Second code breaking change happened to the Run function which now returns IOmniPipeline (i.e. the pipeline interface) itself, not the output blocking collection. Luckily, both changes will be caught by the compiler which would not want to compile the old code any more.

Thursday, August 25, 2011

Multithreading is Hard!

I have known for a long time that there’s a potential race condition between two writers in TOmniBlockingCollection but I thought that it doesn’t present and clear and present danger. Boy was I wrong!

Friday, July 29, 2011

Life after 2.1: Parallel.Join’s new clothes

Parallel.Join has started its life as a very simple construct.
class procedure Join(const task1, task2: TProc); overload;
class procedure Join(const task1, task2: TOmniTaskDelegate); overload;
class procedure Join(const tasks: array of TProc); overload;
class procedure Join(const tasks: array of TOmniTaskDelegate); overload;
Later it got an optional parameter of the IOmnITaskConfig type, but that didn’t change its simplicity. You called Join, it executed some code in parallel, and only when all code blocks completed its execution, your main thread would proceed by executing the statement following the Join call.
Then I started to think about handling exceptions (just as I did for the Parallel.Future) and somehow this simplicity didn’t feel right to me anymore. At the same time I got involved in a prolonged discussion with Антон Алисов (Anton Alisov) and together we defined new features that new Join would have to have.

Thursday, July 28, 2011

OmniThreadLibrary 2.1 hotfix

All users of the 2.1 release, please download this very important hotfix.

There was a nasty bug in OtlEventMonitor where FreeAndNil was called on a variable containing garbage from the stack. >:-(

Great thanks to [Антон Алисов] for finding the problem.

Thursday, July 21, 2011

Life after 2.1: Exceptions in Parallel.Future

The main focus in the next OmniThreadLibrary release is on exception handling in high-level constructs (i.e. the OtlParallel unit). The first one to get this support is Parallel.Future. Why? Simple reason – it has a well-defined point of interaction with the owner (the Value function) and only one background task, which makes exception handling easy to implement.
IOmniFuture<T> was extended with three functions.
  IOmniFuture<T> = interface
    procedure Cancel;
    function  DetachException: Exception;
    function  FatalException: Exception;
    function  IsCancelled: boolean;
    function  IsDone: boolean;
    function  TryValue(timeout_ms: cardinal; var value: T): boolean;
    function  Value: T;
    function  WaitFor(timeout_ms: cardinal): boolean;
  end; { IOmniFuture<T> }
Any exception thrown in the background task and not caught in the future-calculating code will be caught by the IOmniFuture<T> implementation. When a Value is accessed, this exception will be raised in the owner thread.

Wednesday, July 20, 2011

Life after 2.1: Async redux

OtlParallel unit defines four overloaded Async methods in OTL v2.1:

class procedure Async(task: TProc; taskConfig: IOmniTaskConfig = nil); overload;
class procedure Async(task: TOmniTaskDelegate;
taskConfig: IOmniTaskConfig = nil); overload;
class procedure Async(task: TProc; onTermination: TProc;
taskConfig: IOmniTaskConfig = nil); overload;
class procedure Async(task: TOmniTaskDelegate; onTermination: TProc;
taskConfig: IOmniTaskConfig = nil); overload;

As it turned out, two of them are not necessary anymore. Since the introduction of the taskConfig parameter, termination procedure can also be specified by setting taskConfig.OnTerminated.

Tuesday, July 19, 2011

OmniThreadLibrary 2.1

Yes, it is ready. Get the ZIP or check it from SVN.

If you’re following the trunk, do the update. You’ll actually get more than 2.1 as I’ve already merged in development branch with support for exception handling in Parallel.Future and Parallel.Join. Warning – those changes may break the code as two version of Parallel.Async were removed. Check the history.txt and documentation in OtlParallel.pas for more info.

This time you can also download full UML diagrams for OmniThreadLibrary, courtesy of Rich Shealer.

2.1 release should be mostly non-breaking, except for changes in OtlHook exception filtering mechanism and removed EXIT_EXCEPTION exit code (see below for more info).

I’d like to thank dottor_jeckill, Rico Krasowski, vcldeveloper and TOndrej, who helped make this release even more awesomer.

Saturday, July 16, 2011

Getting ready for OmniThreadLibrary 2.1

After a long long wait (sorry folks, due to events out of my control this release took many months longer that I expected) OmniThreadLibrary 2.1 is finally ready!

I’m just putting together change log, testing demos to see if everything is working as it should and so on … A day or two and it will be packed and ready to go. If you’re impatient, just go ahead and check out the current version from the SVN – all the code is already in there.

I have a small favor to ask, though. If you’re using OmniThreadLibrary in D2009 or D2010 – can you please make sure that all tests are included in the appropriate Tests.<version>.groupproj file (and create missing <project name>.<version>.dproj files in the process)? And send the changes to me, of course – my email address is in OTL source files. It would be best if you can leave a comment here if you choose to help me so that the work won’t be duplicated by other programmers.

Thanks in advance, that will really help me getting OTL out quickly. (Otherwise I have to set up a virtual machine and install D2009 and D2010 as I’m not using them for everyday work anymore.)

EDIT: D2010 projects and updated test group are now in the repository, thanks to [vcldeveloper].

EDIT: D2009 projects and updated test group are now in the repository, thanks to [TOndrej].

Saturday, June 25, 2011

Sleep Sort in OTL

I found Sleep Sort so ingenious (in the mad genius way) that I just had to implement it using the OmniThreadLibrary framework.

The code is now shorter than Serg’s original implementation and it’s … wait for it, wait for it … even faster! Twice as fast as the original, actually! Now that I call an improvement!

The code below carries not copyright nor copyleft and can be used in any occasion as long as you don’t blame me for getting fired or any other problems in your personal or professional life it may cause.

Friday, June 10, 2011

Lock-free vs. Locking: Rematch!

My article on lock-free vs. locking data queues was well-received but there were also some comments and complaints. To answer the critics (your comments were all very appreciated!) and to fix some issues with the previous test I’ve decided to stage a rematch.

New contestants

Both Iztok and Chris have provided me with new versions of their queue implementations. Iztok’s code was tuned a little and changed to use TOmniValue instead of TAnyValue for better comparison with TOmniQueue. Chris has created three different variants of his code.

Thursday, June 02, 2011

OmniThreadLibrary Needs YOU!

That is, if you are a C++Builder programmer and want to help an open source project.

image

The problem with OmniThreadLibrary and C++Builder is very simple – I’m not using it. (The C++Builder part, obviously.) Therefore I’m not checking for compatibility with C++Builder and I cannot fix the stuff if it doesn’t work. (In C++Builder.)

And now a user reported that the OTL doesn’t compile. In C++Builder. And I don’t know how to help him. With his problems. In C++Builder.

[BCC32 Error] DSiWin32.hpp(36): E2257 , expected

[BCC32 Error] DSiWin32.hpp(346): E2040 Declaration terminated incorrectly

[BCC32 Error] OtlCommon.hpp(305): E2238 Multiple declaration for 'TOmniValueContainer::Item'

[BCC32 Error] OtlCommon.hpp(304): E2344 Earlier declaration of 'TOmniValueContainer::Item'

[BCC32 Error] OtlSync.hpp(33): E2113 Virtual function '_fastcall IOmniCriticalSection::Release()' conflicts with base class 'IUnknown'

[BCC32 Error] OtlSync.hpp(74): E2113 Virtual function '_fastcall IOmniResourceCount::Release()' conflicts with base class 'IUnknown'

Is there a nice soul out there that can tell me how to fix the problem? (Or even better, who can make sure that the OmniThreadLibrary compiles with C++ Builder.) Your fixed will be gratefully imported into the main development branch and you’ll earn an eternal fame.

Thursday, May 26, 2011

Lock-free vs. locking

For the past few days I was running tests on three different queue implementations – one lock-free, one based on Delphi’s TQueue<T> and TMonitor and one implemented using critical section and linked list. For a good measure I’ve also thrown a blocking wrapper around the lock-free queue into the mix. [Mostly because I’m using it a lot (it has useful features for multithreading work) and I wondered how much time penalty it adds to my applications.]
During that time I’ve discovered a showstopper bug in TMonitor which practically made TSimpleThreadedQueue useless when using more than one reader. Still, I’m including partial results for that implementation too, as they provide a good comparison.

Tuesday, May 24, 2011

TMonitor bug?

When Chris Rolliston implemented a simple threaded queue class using TMonitor, I was quite ecstatic. Finally I will be able to compare my lock-free queue with a threaded implementation! (That’s something I wanted to do for a long time but I never found a willpower to write a locking queue.)
My elation continued while I was coding my test app and while I tested my own queue. And then I plugged in Chris’ queue and … everything went downhill :( Immediately, my test app started crashing. At first it looked like the bug was in Chris’ code, but when I enabled debug DCUs, debugger pointed to a very unlikely location – TMonitor. Unlikely because of two reason – because I know that Delphi people take quality to the heart and test the code and because I know Allen is an experienced guy who writes excellent code.

Sunday, May 15, 2011

TDM Rerun #17: Put It In A Tree

Hierarchical data appears everywhere and most of the time it must be rebuilt from simple non-hierarchical storage. Think about mail, news, CVS repositories and databases, not to mention groupware and chat forums. Trees are everywhere.

- Put It In A Tree, The Delphi Magazine 118, June 2005

This article dealt with thread sorting, an algorithm that takes a number of items connected with parent-child relationship and puts them into a tree so that they can be displayed in a nice structured way. The ideas and implementation are still perfectly valid.

Links: article (PDF, 82 KB), source code (ZIP, 241 KB).

Divide and Conquer (in parallel)

One of the latest additions to the high-level OtlParallel constructs, Fork/Join, was implemented just before ADUG 2011 and presented there for the first time. Shortly after the ADUG I improved the Fork/Join a little but then forgot to blog about it as I was busy implementing Parallel.Async and Parallel.TaskConfig. Sorry :(
Fork/Join helps you solve just one class of problems, but it is an important one – the problems that can be solved by so-called Divide and Conquer algorithm.
For deeper discussion of D&C, read the Wikipedia article linked above. What interests us is that D&C works by subdividing the problem. Instead of trying to solve the big problem, we divide it into many smaller problems and then we try to solve them. Those subproblems may again be too big and have to be subdivided even further. The process continues until the subproblems are small enough that they can be solved easily.
Of particular interest to us are D&C algorithms where subproblems can be solved in parallel.

Tuesday, April 26, 2011

Configuring background OtlParallel tasks

High-level OmniThreadLibrary parallelism (i.e. the OtlParallel unit) is great when you are running mostly independent parts of code but what can you do when you want to communicate with the main thread from a task?
A few weeks ago my answer would be along the lines of setting communication channel manually or dropping down to low-level parallelism (i.e. the CreateTask) but both are very complicated solutions. There was certainly a room for better solution.
Since the release 910, released on April 17th, OtlParallel contains much simpler way to configure tasks and to set them up for communication with the owner.

Sunday, April 17, 2011

Simple background tasks with OtlParallel

While there’s a simple way to execute one-shot background threads with the low-level OTL API (by calling CreateTask), there is no such high-level function in OtlParallel. At least, there wasn’t one until release 899 was committed to the SVN. (Incidentally, that happened 11 days ago but I was silent about it because I was working on another feature – TaskConfig – which will be completed “really soon now”.)
In short, Parallel.Async accepts an anonymous method, normal method or procedure (all of them must be without parameters) and executes it in a background thread. That’s all.

Thursday, March 31, 2011

ADUG 2011 Slides

My presentation from ADUG 2011 is now online at http://www.thedelphigeek.com/p/presentations.html.

Check out the handouts document as it contains lots of my previous writing on OmniThreadLibrary (high-level stuff) neatly collected and organized into one document.

ADUG 2011 - presenters

Thursday, March 24, 2011

Delphi Down Under

This year’s Australia Delphi User Group symposium is a two day event with sessions in Melbourne and Sydney. The first of those – the Melbourne session – happened today. We met in the John Scott Meeting House at the La Trobe university.

image
Turnout was quite big – nearly 80 very attentive listeners.
listeners

Saturday, March 19, 2011

GpProfile on Google code

You may know that lifetime ago I developed fairly successful Delphi profiler called GpProfile.

You may also know that it kinda slipped into oblivion and that it can’t correctly profile modern Delphi code (it is a source instrumenting profile, i.e. it changes your source code so it can be profiled).

You may know all that but I’m fairly sure that you don’t know that GpProfile now works for all Delphis up to XE! How can I be so sure? Because I only learned this a short time ago!

Антон Алисов (Anton Alisov) was brave enough to step in, update the code and create the Google code archive. Go Anton!

In case you’re still using GpProfile (or just want to find out why it was one of most popular Delphi profilers), visit gpprofile2011 project on Google code.

Wednesday, March 16, 2011

Synchronize comes to OmniThreadLibrary

This just came in:

  • IOmniTaskControl.Invoke(procedure begin … end)
  • IOmniTaskControl.Invoke(procedure (const task: IOmniTask) begin … end)
  • IOmniTask.Invoke(procedure begin … end)

Still missing:

  • IOmniTask.Invoke(procedure (const task: IOmniTaskControl) begin … end)

Monday, February 14, 2011

Parallel for implementation [3]: Output

In the previous two installments I’ve tried to give a little insight into how OmniThreadLibrary’s Parallel ForEach is implemented (part 1 – Overview, part 2 – Input). Today I will conclude this short series with the description of output ordering – or what is know in the OTL as the .PreserveOutput modifier.

Ordering is usually used together with the .Into modifier. The reason lies in the integration between the Parallel infrastructure and your parallel code (the one that is executing as Parallel.ForEach payload). In the “normal” foreach statement, output from this parallel payload is not defined. You are allowed to do whatever in the foreach, to generate any output (in case you need it) but Parallel will know nothing about that. Therefore, the OTL has no ability to preserver any ordering because – at least from the viewpoint of the library – the parallelized code is producing no output.

Thursday, February 10, 2011

OmniThreadLibrary Down Under

I’m very excited to announce that OmniThreadLibrary will appear before the Australian public in this year’s ADUG Symposium!

image

This year’s symposium will happen in Melbourne on 24th and in Sydney on 25th of March.

The title of my presentation will be “Getting full speed with Delphi?” and will cover multithreading programming and high-level OmniThreadLibrary stuff.

Getting full speed with Delphi
(Why single threaded is not good enough?)

In the last few years, the traditional approach to speeding up programs ("We'll just wait for the next generation of hardware.") doesn't work anymore.

In this talk, we'll see why Delphi programs use only 12.5 % CPU on a modern machine and what we can do about it.

The session will show you how to make murky waters of multithreading accessible to every Delphi developer with the help of open source OmniThreadLibrary.

In case you want to meet with me and discuss multithreading programming (or anything else, including life, universe and everything), I’ll be available before the Melbourne and after the Sydney event.

Friday, February 04, 2011

How to crash Delphi compiler in four easy steps

Step one

Start Delphi XE.

Step Two

Create simple project.

Tuesday, January 25, 2011

Parallel for implementation [2]: Input

In my last post, I’ve presented an overview of classes hiding behind the parallel for implementation. Today I’ll focus on the input part of the parallel for – the part that fetches values the loop is iterating over and passes them to parallel tasks. More specifically, I’ll present source providers, data managers and local queue.

Tuesday, January 11, 2011

Parallel for implementation [1]: Overview

Aeons ago I promised to write a blog post about all the magic that happens behind the scenes in Parallel.ForEach. That never happened (sorry). I was busy will other stuff and I had to put it on the backburner.

Today is the day to fulfill that promise.

This article starts the journey that will (hope, hope) explain the murky waters of parallel loop data management. Three parts are planned – Overview (which you are reading now), Input and Output.

Even if you are interested in parallel programming, you may think that such low-level stuff is of no interest to you. Well, you may be right, but let me state three reasons why you should read this three-part series.

1) Because you will then know what the OtlDataManager unit is good for and will be able to use it in your application.

2) Because it’s an interesting topic ;)

3) So I can convince you that Parallel.ForEach is better than home-brew multithreaded parallel loops and that you should always use OmniThreadLibrary ;)

Ready?

Thursday, January 06, 2011

Delphi on wide screen

A lifetime ago when I was still programming on two 1280 × 1024 monitors I’ve published a post about the IDE layout I was using at that time (in Delphi 2006).

I was always saying that there’s only one reason why a programmer should use two monitors – because (s)he has no place for the third one! So when the opportunity knocked I did the same – cleaned up some place on the desk and installed a 1920 × 1200 monitor in the middle.

Sunday, January 02, 2011

GpLists and GpStructuredStorage update

GpLists 1.49: Implemented TGpGUIDList, a TGUID list.

GpStructuredStorage 2.0c: Uses GpStreams instead of (deprecated) GpMemStr.

Erik Berry fixed GpTextStream and GpLists to compile with Delphi 6; those changes were committed to SVN only.

Friday, December 31, 2010

Happy New Year 2011

shadows

See you around in 2011 – with some luck maybe even in person.

[Picture of the living room wall taken by my trusty Panasonic Lumix DMC-LX5 and heavily processed in Adobe Photoshop Lightroom 3.]

Saturday, December 25, 2010

Gp* Holiday Update

As always, all units are available on the Google Code.

DSiWin32 1.60

  • When compiled with D2007 or newer, unit FileCtrl is not included.
  • Call UniqueString before calling CreateProcessW.
  • [Tommi Prami] Added types missing in Delphi 7.
  • Added function DSiDisableStandby that will try to disable standby and hibernate on Windows XP SP 2 and newer.
  • Define TStartupInfoW in Delphi 7 and earlier.
  • DSiAddApplicationToFirewallExceptionList[Advanced|XP] got a new parameter
    TDSiFwResolveConflict (default rcDuplicate) where the caller can specify
    behaviour if the rule with the same name already exists.
    [rcDuplicate = add new rule with the same name, rcOverwrite = remove all rules
    with the same name and then add the new rule, rcSkip = leave existing rules
    intact and don't add the new rule]
  • Implemented DSiFindApplicationInFirewallExceptionList[Advanced|XP].
  • Bug fix in DSiAddApplicationToFirewallExceptionListAdvanced: setting rule.ServiceName to '' caused fwPolicy2.Rules.Add(rule) to raise exception.

Monday, December 13, 2010

You’ve got mail!

It was only three days ago that I released the new OTL and already I’ve got a gift – and it came from the other side of the world, from a place so far ago that Google Maps doesn’t know how to calculate directions to guide me there, from Australia!

sea mail

No, I’m not kidding about the Google Maps.

gmaps

Inside were books, books and more books. Chris, thanks a lot!

Friday, December 10, 2010

Out with the old … in with the two

OmniThreadLibrary 1.05 was a great success …

image

… but all good things must come to an end. Don’t worry, I’m not ending the project. It’s just that there’s a new player in town. Ladies and gentlemen, in the left corner I give you …

image

… OmniThreadLibrary 2.0! Get it while its hot!

Thursday, December 02, 2010

OmniThreadLibrary 2.0 TODO

Only few things to do before the alpha release:

  • Parallel.Pipeline must support cancellation;
  • Parallel.ForEach would benefit from task-local state (maybe will be implemented after the 2.0 release);
  • Cleanup various small TODOs;
  • Add project files for Delphi XE;
  • Retest everything.

Wednesday, December 01, 2010

OmniThreadLibrary Documentation

Thanks to the great people of DevJET software there may something (finally) happen on the very much neglected documentation front. They have donated a Documentation Insight license to the OmniThreadLibrary and I intend to use it to add documentation here and there while I’m working on the project.

A big Thank You to the DevJET!

Documentation Insight & OmniThreadLibrary

The next part of the puzzle is how to export XmlDoc documentation into some useful form. I know Delphi XE can do html+javascript export but I don’t believe that it’s included in the Professional release which I have (but correct me if I’m wrong). It would be even better if it could be converted into the Wiki format used by the Google Code. Can you help me with suggestions?

Tuesday, November 23, 2010

Multistage processes with the OmniThreadLibrary

The OtlParallel unit in OmniThreadLibrary offers some high-level solutions that allow you to easily run some kinds of processes in parallel. Up to now it supported self-contained background calculations (Parallel.Future), independent parallel processes (Parallel.Join) and loop calculations where the background task is stateless (i.e. it only depends on the input – the loop value – and not on calculations done on other inputs – loop values; Parallel.ForEach). But lots of time processes don’t fall into any of those categories.

Mason Wheeler recently suggested adding support for multistage processes. Over the weekend I’ve implemented it in the OmniThreadLibrary and now this feature is ready for you to start testing. Great thanks to Mason for his suggestion and also for work on the implementation and design of newly introduced Parallel.Pipeline.

Saturday, November 20, 2010

ITDevCon 2010

ITDevCon has finished almost a 24 hours ago but I was simply too tired to write anything about it until now. In short – great event!

There was close to 50 participants and sessions were in most cases nicely filled up. Three tracks were running in parallel and sometimes it was quite hard to choose the most interesting session. I was quite sad as I was not able to see any of Alexander Alexeev’s sessions on debugging (the first one overlapped with my own session and in the second case seeing Ray Konopka speaking of user interface design trumped all other options). Besides Ray session which was definitely the best on the ITDevCon (Ray told me to say so ;) ) I have to mention Paweł’s expose on DataSnap and Thierry’s multitouch session which were both very interesting.

Monday, November 15, 2010

Embarcadero tech support should pull its act together

For the past few days I have fought a small war with the Embarcadero registration system. For some unknown reason, Delphi XE installed fine but when I tried to register it, I got back
“No  valid  license information found for Embarcadero(R) Delphi(R) XE.
You  must provide a valid serial number in order to use Embarcadero(R)
Delphi(R) XE. Do you want to run the registration wizard again?”
The funny thing was that my registration count got incremented nevertheless! Of course I only noticed this after five failed installs when the sixth attempt told me that I’ve used my installation bonus and I can install no more Delphis :( Most probably there was some clash between the fresh Delphi XE installation, previous trial version and pre-previous [sorry I can’t tell you about it] version. Of course, I did try to fully remove all remnants of all installations but obviously I missed some important part.
At that point I did the right thing and opened a support case. A guy from Embarcadero support responded soon enough with a note that he bumped my registration count and I can retry. Of course I already knew that retrying won’t help so I asked him how to fully clean up my machine.
Then I waited 24 hours …
Next day I sent few more mails and finally got a pretty comprehensive clean-up list. Then only problem was that it was completely b0rken (as you’ll see in a second).
So I sent a response to that mail, requesting clarification of some items.
No reply.
Then the weekend occurred …
Nothing happened yesterday either. At last I sent another mail urging the support to please respond to my question and bump my registration count again (as I was already up to 10 registrations – only one of them really successful, and that one was on another machine).
Finally I got the reply. Actually, I received a mail stating that my registration count was bumped again. Nothing else. No reply to any of my questions. Nada, zip, zilch.
It looks like Embarcadero has tech support that can only do two things. 1. Bump registration count. 2. Send around bad instructions on how to remove remnants of Delphi from your system.
Sad smile
Embarcadero people, if you really want Delphi to be successful again, you should educate your tech support.
Luckily, I know enough about Delphi to clean my system even without answers to my questions so I was able to finally install XE. Hurrah!
I still have to prove that the cleanup list is really really bad, yes? Well, here it is, directly pasted from the support mail. My comments are in italic.
1. Uninstall the product via the "Embarcadero Rad Studio 2010" entry in "Uninstall a Program" in the Control Panel
I’m trying to uninstall Delphi XE so “Embarcadero RAD Studio XE” would be a better choice.
2. Remove the C:\Program Files\Codegear\Rad Studio\8.0 directory

Actually, folder is named \Embarcadero\, not \Codegear\.
3. Remove the C:\Users\Public\Public Documents\Rad Studio directory
That would trash the Delphi 2010 install. Only 8.0 subfolder has to be removed.
4. Remove the c:\ProgramData\CodeGear\Rad Studio\8.0 directory
Again, it’s \Embarcadero\.
5. Remove the HKEY_LOCAL_MACHINE\SOFTWARE\CodeGear\BDS\8.0 registry key
Same here.
6. Remove the HKEY_CURRENT_USER\SOFTWARE\CodeGear\BDS\8.0 registry key
And here.
7. Remove the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{A2B58B18-5D04-4006-9713-B6945880746E} registry key
8. Remove the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CodeGear RAD Studio 2010 registry key
Embarcadero RAD Studio XE, not CodeGear RAD Studio 2010.
9. Remove folders with a GUID name in C:\Documents and Settings\All Users\Application Data\   
In item 3, C:\Users was used. Here, C:\Documents and Settings. On every computer, one of those will not be the correct choice.
9a. You can find the specific GUID folder names to remove by browsing to the subkeys of HKEY_LOCAL_MACHINE\Software\MimarSinan\InstallAware\Ident.Cache\
10. Remove the following files from Windows\System32:   
10a. *120.bpl   
10b. *120.jdbg   
10c. *120.xml   

In Delphi XE, those files end in 150, not 120. And on a 64-bit system they live in \Windows\SysWOW64.
10d. bdeadmin.*   
10e. cc32*.dll   
10f. midas.*

Dear reader, please tell me – am I overreacting? Or somebody should be fired here for not doing his/her work (and I definitely don’t mean the poor tech support guy I was talking to)?

Tuesday, November 09, 2010

Blaise Pascal Magazine Rerun #3: Real World Enumerators

This article was originally written for the Blaise Pascal Magazine and was published in Issue #5.

Relevant Delphi code is available at http://17slon.com/blogs/gabr/BPM/RealWorldEnumerators.zip

Friday, November 05, 2010

Blaise Pascal Magazine Rerun #2: Advanced Enumerators

This article was originally written for the Blaise Pascal Magazine and was published in Issue #4.

Relevant Delphi code is available at http://17slon.com/blogs/gabr/BPM/AdvancedEnumerators.zip.

Tuesday, November 02, 2010

Blaise Pascal Magazine Rerun #1: Introduction to Enumerators

This article was originally written for the Blaise Pascal Magazine and was published in Issue #3.

Tuesday, October 05, 2010

Too many what?

image

Delphi 2007.

Conditional symbols:

xFullDebugMode;xUseReservationList;xSimulateDVBMaster;xNoDongle;NoExcept;NoTrace;xLogDriverCalls;xNoDVBMaster;DEBUG;xDuplicateOutputToSimulator;xLogDelaying;TestSubtitleDelay;CatchUseOfFreedInterfaces;LockDriverCalls;NoDVBNowAdjustment;DetailedTooLateError

16 symbols.

257 characters in total.

Too many? Was Delphi 2007 built in DOS times?

Can somebody please check this with Delphi XE?

Friday, September 03, 2010

Ingenious!

Sometimes you find a code fragment that’s so great you only wish it was your idea …
const
  fm: array[Boolean] of Word = (fmCreate, fmOpenWrite);
fs := TFileStream.Create(fileName, fm[FileExists(fileName)]);

Obvious – in retrospective.

Wednesday, August 18, 2010

OmniThreadLibrary webinar – recording

While I was on vacation, Robert published a recording of my OmniThreadLibrary webinar. Happy downloading!

Friday, July 23, 2010

So terribly sorry …

Writing code ain’t that hard a job.

Writing correct code, well that’s a much harder venture.

And what can I say about writing correct multithreaded code? Only that it’s close to impossible.

That’s exactly why I started writing OmniThreadLibrary – I needed well-tested framework for multithreading processing.

But alas! there are bugs in OmniThreadLibrary too. Not many of them, true, but still they are there. Some are squashed soon, other remain hidden for a long time.

I found one such bug few days ago when I was searching for a reason why some code doesn’t parallelize well. In theory the speedup should be close to 8x (on a 8 core machine) but in practice the parallel code was only faster by a factor of 2 to 3.

At the end of a long day I found out a bug in the TOmniBlockingCollection that prevented all threads to be executing at once. Only two or three threads were really working and they did all the job – but only two to three times faster, of course.

The bug is now fixed in the trunk. Anybody can do a checkout and get a perfect (well, maybe not perfect but definitely a better-working) code.

Because this was quite an important fix I’ve also incorporated it into the 1.05 version of this unit. You can download it here. If you’re using 1.05 and TOmniBlockingCollection, you surely want to download the update.

I’m really sorry for letting this stupid bug slip through my testing. Won’t happen again. (Or maybe it will. Probably it will. Oh, heck, it surely will. I’ll just try to make such problems very rare. Promise.)

Monday, July 19, 2010

Scheduled OmniThreadLibrary presentations

On July 27th, I’ll be speaking for the Virtual Delphi Users Group. The topic will be “Parallel programming with OmniThreadLibrary”. Be aware that you have to register in advance if you want to participate (all questions will be answered!). The recording will be available some time after the presentation. [At the moment, the VDUG server has some occasional problems so be patient and/or retry later.]

On November 18 and 19, I'll be speaking at ITDev Con 2010. Two of my presentations will focus on OmniThreadLibrary and the third one on memory management with FastMM. All presentations will be given in English language.

Monday, July 12, 2010

TDM Rerun #16: Thread Pooling, The Practical Way

As we found out, the system thread pool in Windows 2000 (plus XP and 2003) is woefully inadequate for any serious use. It seems that its designer was only thinking about really trivial usage and expected everyone else to create their own thread pool. Luckily, it was possible to create a fully-fledged pooling layer based on the system thread pool and the application was saved.
- Thread Pooling, The Practial Way, The Delphi Magazine 112, December 2004
The December 2004 issue describes one of my first serious forays into the muddy waters of parallel processing. The article describes a work item pooling mechanism built in Windows (QueueUserWorkItem) and a management wrapper that I built around this API to make its use bearable.
The GpWinThreadPool unit (described in this article) has been later replaced with a TThread-based pool of my own design and that unit (GpThreadPool) was superseded by the thread pool built in the OmniThreadLibrary. The use of the code described in this TDM article is not really recommended (except maybe for the educational purposes).
Links: article (PDF, 116 KB), source code (ZIP, 2,6 MB).

Wednesday, June 30, 2010

Gp* units now available via SVN

Because YOU asked for it … my units are now available on Google Code.

Tuesday, June 29, 2010

Important DSiWin32 and GpSecurity update

1) Lots of things fixed in DSiWin32 and great thanks to Christian Wimmer for pointing out the problems and suggesting some solutions.

2) By my mistake a very internal GpSecurity containing parts of JWA got included in some downloadable ZIP files. This was a direct violation of the JWA license and I apologize deeply for that. To fix this problem, a new GpSecurity was released which depends on the JWA.

Monday, June 21, 2010

Built for speed

Unlike C and derivatives, Delphi is speedy …

build

174.684 lines per second. What’s your compile speed?

Wednesday, June 16, 2010

The Future of Delphi

Future of T, that is. Or, in Delphi syntax, TFuture<T>.
Yesterday I wrote about futures in OmniThreadLibrary 2.0 (supported only in D2009+) and I mentioned that implementing futures in plain D2009+ should be really simple. And it really is – it took me all of 15 minutes to write the supporting library and a simple test case.
The code below is released to public domain. I’m claiming no copyrights – use it as you wish. You don’t even have to attribute it to me. Just don’t use it for evil purposes ;)
unit DelphiFuture;

interface

uses
  Classes;

type
  IFuture<T> = interface
    function Value: T;
  end;

  TFutureDelegate<T> = reference to function: T;

  TFutureThread<T> = class(TThread)
  strict private
    FAction: TFutureDelegate<T>;
    FResult: T;
  public
    constructor Create(action: TFutureDelegate<T>);
    procedure Execute; override;
    property Result: T read FResult;
  end;

  TFuture<T> = class(TInterfacedObject, IFuture<T>)
  strict private
    FResult: T;
    FWorker: TFutureThread<T>;
  public
    constructor Create(action: TFutureDelegate<T>);
    function Value: T;
  end;

implementation

uses
  SysUtils;

{ TFutureThread<T> }

constructor TFutureThread<T>.Create(action: TFutureDelegate<T>);
begin
  inherited Create(false);
  FAction := action;
end;

procedure TFutureThread<T>.Execute;
begin
  FResult := FAction();
end;

{ TFuture<T> }

constructor TFuture<T>.Create(action: TFutureDelegate<T>);
begin
  inherited Create;
  FWorker := TFutureThread<T>.Create(action);
end;

function TFuture<T>.Value: T;
begin
  if assigned(FWorker) then begin
    FWorker.WaitFor;
    FResult := FWorker.Result;
    FreeAndNil(FWorker);
  end;
  Result := FResult;
end;

end.
I’ve used my usual test case, calculating number of primes between 1 and 1.000.000.
implementation

uses
  DelphiFuture;

function IsPrime(i: integer): boolean;
var
  j: integer;
begin
  Result := false;
  if i <= 0 then
    Exit;
  for j := 2 to Round(Sqrt(i)) do
    if (i mod j) = 0 then
      Exit;
  Result := true;
end;

procedure TForm1.btnTestClick(Sender: TObject);
var
  numPrimes: IFuture<integer>;
begin
  numPrimes := TFuture<integer>.Create(function: integer
    var
      iPrime: integer;
    begin
      Result := 0;
      for iPrime := 1 to 1000000 do
        if IsPrime(iPrime) then
          Inc(Result);
    end
  );
  lbLog.Items.Add(Format('%d primes from 1 to 1000000',
    [numPrimes.Value]));
end;

Tuesday, June 15, 2010

OmniThreadLibrary 2.0 sneak preview [2]

Futures in the OTL were not planned – they just happened. In fact, they are so new that you won’t find them in the SVN. (Don’t worry, they’ll be committed soon.)

As a matter of fact, I always believed that futures must be supported by the compiler. That changed few weeks ago when somebody somewhere (sorry, can’t remember the time and place) asked if they can be implemented in the OmniThreadLibrary. That question made me rethink the whole issue and I found out that not only it’s possible to implement them without changing the compiler – the implementation is almost trivial!

In the OTL 2.0 you’ll be able to declare a future …

var
numPrimes: IOmniFuture<integer>;

… start the evaluation …

  numPrimes := TOmniFuture<integer>.Create(a delegate returning integer);

… and wait on the result.

  numPrimes.Value

As simple as that. Declare the IOmniFuture<T>, create TOmniFuture<T> and retrieve the result by calling Value: T.

As a real-world example, the code below creates a future that calculates number of primes from 1 to CPrimesHigh and displays this value.

var
numPrimes: IOmniFuture<integer>;
begin
numPrimes := TOmniFuture<integer>.Create(function: integer
var
i: integer;
begin
Result := 0;
for i := 1 to CPrimesHigh do
if IsPrime(i) then
Inc(Result);
end
);
// do something else
lbLog.Items.Add(Format('%d primes from 1 to %d',
[numPrimes.Value, CPrimesHigh]));
end;

As a general rule, I would recommend against putting too much of the code inside the future’s constructor. A following approach is more readable and easier to maintain.

function CountPrimesToHigh(high: integer): integer;
var
i: integer;
begin
Result := 0;
for i := 1 to CPrimesHigh do
if IsPrime(i) then
Inc(Result);
end;

var
numPrimes: IOmniFuture<integer>;
begin
numPrimes := TOmniFuture<integer>.Create(function: integer
begin
Result := CountPrimesToHigh(CPrimesHigh);
end
);
// do something else
lbLog.Items.Add(Format('%d primes from 1 to %d',
[numPrimes.Value, CPrimesHigh]));
end;

Or you can take another step and create a future factory. That’s especially recommended if you’ll be using futures of the same kind in different places.

function StartCountingPrimesTo(high: integer): TOmniFuture<integer>;
begin
Result := TOmniFuture<integer>.Create(function: integer
var
i: integer;
begin
Result := 0;
for i := 1 to high do
if IsPrime(i) then
Inc(Result);
end
);
end;

var
numPrimes: IOmniFuture<integer>;
begin
numPrimes := StartCountingPrimesTo(CPrimesHigh);
// do something else
lbLog.Items.Add(Format('%d primes from 1 to %d',
[numPrimes.Value, CPrimesHigh]));
end;

Implementation

Believe it or not, the whole implementation fits in 27 lines (not counting empty lines).

type
TOmniFutureDelegate<T> = reference to function: T;

IOmniFuture<T> = interface
function Value: T;
end; { IOmniFuture<T> }

TOmniFuture<T> = class(TInterfacedObject, IOmniFuture<T>)
private
ofResult: T;
ofTask : IOmniTaskControl;
public
constructor Create(action: TOmniFutureDelegate<T>);
function Value: T;
end; { TOmniFuture<T> }
constructor TOmniFuture<T>.Create(action: TOmniFutureDelegate<T>);
begin
ofTask := CreateTask(procedure (const task: IOmniTask)
begin
ofResult := action();
end,
'TOmniFuture action').Run;
end; { TOmniFuture<T>.Create }

function TOmniFuture<T>.Value: T;
begin
ofTask.Terminate;
ofTask := nil;
Result := ofResult;
end; { TOmniFuture<T>.Value }

As you can see, the whole OTL task support is only used to simplify background thread creation. It would be quite simple to implement futures around Delphi’s own TThread. In fact, I think I’ll just go ahead and implement it!

Monday, June 14, 2010

OmniThreadLibrary 2.0 sneak preview [1]

You may have noticed that I’ve been strangely silent for the past two months. The reason for that is OmniThreadLibrary version 2. [And lots of other important work that couldn’t wait. And the OmniThreadLibrary version 2.]

The OTL 2.0 is not yet ready but I’ve decided to pre-announce some features. They are, after all, available to all programmers following the SVN trunk.

While the focus of the OTL 1 was to provide programmers with simple to use multithreading primitives, OTL 2 focuses mostly on the higher-level topics like parallel for and futures.

Caveat: Parallel For and Futures will work only in Delphi 2009 and newer. The implementation of both heavily depends on generics and anonymous methods and those are simply not available in Delphi 2007. Sorry, people. [I’m sad too – I’m still using Delphi 2007 for my day job.]

Parallel For

Parallel.ForEach was introduced in release 1.05 but that version was purely “technical preview” – a simple “let’s see if this can be done at all” implementation. In the last few months, Parallel.ForEach backend was completely redesigned which allowed the frontend (the API) to be vastly improved.

The basic ForEach(from, to: integer) has not changed much. The only difference is that the parameter type of the Execute delegate is now “integer” and not “TOmniValue”.

  Parallel.ForEach(1, testSize).Execute(
procedure (const elem: integer)
begin
if IsPrime(elem) then
outQueue.Add(elem);
end);

A trivial example, of course, but it shows the simplicity of Parallel.ForEach. The code passed to the Execute will be executed in parallel on all possible cores. [The outQueue parameter is of type TOmniBlockingCollection which allows Add to be called from multiple threads simultaneously.]

If you have data in a container that supports enumeration (with one limitation – enumerator must be implemented as a class, not as an interface or a record) then you can enumerate over it in parallel.

  var
nodeList := TList.Create;
Parallel.ForEach<integer>(nodeList).Execute(
procedure (const elem: integer)
begin
if IsPrime(elem) then
outQueue.Add(elem);
end);

The new ForEach backend allows parallel loops to be executed asynchronously. In the code sample below, the parallel loop tests numbers for primeness and adds primes to a TOmniBlockingCollection queue. A normal for loop, executing in parallel with the parallel loop, reads numbers from this queue and displays them on the screen.

var
prime : TOmniValue;
primeQueue: IOmniBlockingCollection;
begin
lbLog.Clear;
primeQueue := TOmniBlockingCollection.Create;
Parallel.ForEach(1, 1000).NoWait
.OnStop(
procedure
begin
primeQueue.CompleteAdding;
end)
.Execute(
procedure (const value: integer)
begin
if IsPrime(value) then begin
primeQueue.Add(value);
end;
end);
for prime in primeQueue do begin
lbLog.Items.Add(IntToStr(prime));
lbLog.Update;
end;
end;

This code depends on a TOmniBlockingCollection feature, namely that the enumerator will block when the queue is empty unless CompleteAdding is called [more info]. That’s why the OnStop delegate must be provided – without it the “normal” for loop would never stop. (It would just wait forever on the next element.)

While this shows two powerful functions (NoWait and OnStop) it is also kind of complicated and definitely not a code I would want to write too many times. That’s why OmniThreadLibrary also provides a syntactic sugar in a way of the Into function.

var
prime : TOmniValue;
primeQueue: IOmniBlockingCollection;
begin
lbLog.Clear;
primeQueue := TOmniBlockingCollection.Create;
Parallel.ForEach(1, 1000).PreserveOrder.NoWait
.Into(primeQueue)
.Execute(
procedure (const value: integer; var res: TOmniValue)
begin
if IsPrime(value) then
res := value;
end);
for prime in primeQueue do begin
lbLog.Items.Add(IntToStr(prime));
lbLog.Update;
end;
end;

This code demoes few different enhacements to the ForEach loop. Firstly, you can order the Parallel subsystem to preserve input order by calling the PreservedOrder function. [In truth, this function doesn’t work yet. That’s the part I’m currently working on.]

Secondly, because Into is called, ForEach will automatically call CompleteAdding on the parameter passed to the Into when the loop completes. No need for the ugly OnStop call.

Thirdly, Execute (also because of the Into) takes a delegate with a different signature. Instead of a standard ForEach signature procedure (const value: T) you have to provide it with a procedure (const value: integer; var res: TOmniValue). If the output parameter (res) is set to any value inside this delegate, it will be added to the Into queue and if it is not modified inside the deletage, it will not be added to the Into queue.  Basically, the parallel loop body is replaced with the code below and this code calls your own delegate (loopBody).

        result := TOmniValue.Null;
while (not Stopped) and localQueue.GetNext(value) do begin
loopBody(value, result);
if not result.IsEmpty then begin
oplIntoQueueObj.Add(result)
result := TOmniValue.Null;
end;
end;
oplIntoQueueObj.CompleteAdding;

The NoWait and Into provide you with a simple way to chain Parallel loops and implement multiple parallel processing stages. [Although this works in the current version, the OtlParallel does nothing to balance the load between all active Parallel loops. I’m not yet completely sure that this will be supported in the 2.0 release.]

var
dataQueue : IOmniBlockingCollection;
prime : TOmniValue;
resultQueue: IOmniBlockingCollection;
begin
lbLog.Clear;
dataQueue := TOmniBlockingCollection.Create;
resultQueue := TOmniBlockingCollection.Create;
Parallel.ForEach(1, 1000)
.NoWait.Into(dataQueue).Execute(
procedure (const value: integer; var res: TOmniValue)
begin
if IsPrime(value) then
res := value;
end
);
Parallel.ForEach<integer>(dataQueue as IOmniValueEnumerable)
.NoWait.Into(resultQueue).Execute(
procedure (const value: integer; var res: TOmniValue)
begin
// Sophie Germain primes
if IsPrime(2*value + 1) then
res := value;
end
);
for prime in primeQueue do begin
lbLog.Items.Add(IntToStr(prime));
lbLog.Update;
end;
end;

[BTW, there will be a better way to enumerate over TOmniBlockingCollection in the OTL 2.0 release. Passing “dataQueue as IOmniValueEnumerable” to the ForEach is ugly.]

If you want to iterate over something very nonstandard, you can write a “GetNext” delegate:

    Parallel.ForEach<integer>(
function (var value: integer): boolean
begin
value := i;
Result := (i <= testSize);
Inc(i);
end)
.Execute(
procedure (const elem: integer)
begin
outQueue.Add(elem);
end);

In case you wonder what the possible iteration sources are, here’s the full list:

    ForEach(const enumerable: IOmniValueEnumerable): IOmniParallelLoop; 
ForEach(const enum: IOmniValueEnumerator): IOmniParallelLoop;
ForEach(const enumerable: IEnumerable): IOmniParallelLoop;
ForEach(const enum: IEnumerator): IOmniParallelLoop;
ForEach(const sourceProvider: TOmniSourceProvider): IOmniParallelLoop;
ForEach(enumerator: TEnumeratorDelegate): IOmniParallelLoop;
ForEach(low, high: integer; step: integer = 1): IOmniParallelLoop<integer>;
ForEach<T>(const enumerable: IOmniValueEnumerable): IOmniParallelLoop<T>;
ForEach<T>(const enum: IOmniValueEnumerator): IOmniParallelLoop<T>;
ForEach<T>(const enumerable: IEnumerable): IOmniParallelLoop<T>;
ForEach<T>(const enum: IEnumerator): IOmniParallelLoop<T>;
ForEach<T>(const enumerable: TEnumerable<T>): IOmniParallelLoop<T>;
ForEach<T>(const enum: TEnumerator<T>): IOmniParallelLoop<T>;
ForEach<T>(enumerator: TEnumeratorDelegate<T>): IOmniParallelLoop<T>;
ForEach(const enumerable: TObject): IOmniParallelLoop;
ForEach<T>(const enumerable: TObject): IOmniParallelLoop<T>;

The last two versions are used to iterate over any object that supports class-based enumerators. Sadly, this feature is only available in Delphi 2010 because it uses extended RTTI to access the enumerator and its methods.

Parallel For Implementation

The backend allows for efficient parallel enumeration even when the enumeration source is not threadsafe. You can be assured that the data passed to the ForEach will be accessed only from one thread at the same time (although this will not always be the same thread). Only in special occasions, when backend knows that the source is threadsafe (for example when IOmniValueEnumerator is passed to the ForEach), the data will be accessed from multiple threads at the same time.

I’m planning to write an article of the parallel for implementation but it will have to wait until the PreserveOrder is implemented. At the moment backend implementation is not fixed yet.

Wednesday, June 09, 2010

A seriously overdue update

DSiWin32 1.55

  • Implemented DSiHasElapsed64 and DSiElapsedTime64.
  • Implemented DSiLogonAs and DSiVerifyPassword.
  • DSiGetProcAddress made public.

GpHugeFile 6.02

  • Prefetching parameters are now configurable -  TGpHugeFileStream.Create and .CreateW got parameters waitObject and numPrefetchBuffers which are passed to ResetEx/RewriteEx.

GpLists 1.44

  • TStringList helper split into TStrings and TStringList helpers

GpStreams 1.30

  • Implemented TGpFileStream class and two SafeCreateGpFileStream functions.
  • Unicode fixes.
  • Disable inlining for Delphi 2007 because of compiler bugs.
  • Added functions AtEnd and BytesLeft, AsAnsiString property and WriteAnsiStr method to the TStream class helper.
  • Implemented TGpFixedMemoryStream.CreateA and fixed TGpFixedMemoryStream.Create.

GpStructuredStorage 2.0b

  • Important bug fix! When the folder was deleted, it was not removed from the folder cache. Because of that, subsequent FolderExists call succeeded instead of failed, which could cause all sorts of weird problems.

GpStuff 1.21

  • Implemented overloads for Increment and Decrement in TGp4AlignedInt and TGp8AlignedInt64.
  • Implemented Add/Subtract methods in TGp4AlignedInt and TGp8AlignedInt64.
  • OpenArrayToVarArray supports vtUnicodeString variant type.

GpSync 1.23

  • Message queue works with Unicode Delphi, backwards compatible.

GpTextStream 1.08

  • Implemented 'lines in a text stream' enumerator EnumLines.
  • Implemented TGpTextStream.EOF.
  • Implemented text stream filter FilterTxt.

All free as usual. Enjoy!

Monday, June 07, 2010

What drives us

Monkeys work harder when they are not rewarded. People do, too.

Daniel H. Pink [wikipedia] collected the evidence about that fact and wrote (supposedly very good, didn’t read it yet) book Drive.

That’s not why I’m writing this post.

People are asking me from time to time why do I put so much work into providing free code and knowledge to the community.

My usual answer to that is: “Er, that’s hard to explain. I feel the need.” (Yep, that kind  of need.)

But that’s also not why I’m writing this post.

Not so much ago, RSA Animate published an 11-minute YouTube video containing a concentrated version of Daniel Pink’s talk based on the Drive book.

Now that’s why I’m writing this post!

This concentrated version of the book is so great that I definitely want to read the whole thing (in fact I already bought the Kindle version).

Even more – at 8:44 it defines me in few words: “Challenge, mastery and making a contribution.”

Exactly! I need the challenge, I want to master the subject and then I want to make a contribution!

Thanks to Dan Pink and the great people at RSA Animate I learned something about myself.

Sunday, June 06, 2010

Synchronisation in a multithreaded environment

Blaise Pascal #11 is out containing the third installment of my multithreading series, this time dealing with the synchronisation.

Monday, April 19, 2010

ParallelExtensionExtras

I’d just like to point out to all parallel-loving programmers that Parallel Programming with .NET blog posted a series of  11 articles (more to come) called A Tour of ParallelExtensionExtras. A gread read, full of interesting information and some ideas that could find its way into the OTL (which is, by the way, getting full Parallel.For support in these weeks).