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)

Invoke allows you to execute a code fragment in the context of another thread, just like Synchronize and Queue do. Actually, Invoke works just like Queue – and not like Synchronize – in that that it schedules the code over the communication channel without any control when it will actually be executed. Invoked code will only be executed when the target thread processes messages. [I used “Synchronize” in the title because most people that like to use TThread.Synchronize don’t even know about TThread.Queue.]

You can now write stuff like this:

var
formThreadID: DWORD;
begin
formThreadID := GetCurrentThreadID;
// FTask: IOmniTaskControl
FTask.Invoke(
procedure (const task: IOmniTask)
var
taskThreadID: DWORD;
begin
// this will execute in the context of the worker thread
taskThreadID := GetCurrentThreadID;
task.Invoke(
procedure
begin
// this will execute in the context of the main thread
frmInvokeAnonymousDemo.lbLog.Items.Add(Format(
'Current thread ID: %d, task thread ID: %d, ' +
'form thread ID: %d',
[GetCurrentThreadID, taskThreadID, formThreadID]));
end
);
end
);
end;

Pre-emptive answers:

  1. No, I will not implement blocking version (i.e. Synchronize). Ever.

  2. No, I will not implement Invoke(TMethod) or Invoke(TProcedure). Most of the power of Invoke(TProc) comes from the ability of anonymous method to capture variables.

5 comments:

  1. Gabriel, you are the best!

    ReplyDelete
  2. Oops - sorry: "Primoz"

    ReplyDelete
  3. I was kinda hoping you would call this "Unsynchronize()" just to make a point. But I have an odd sense of humour. I can see this being very useful for my DB code, if I can get Pete to implement it.

    ReplyDelete
  4. Can Queue be preemptive ?

    For example, background tasks does long calculation and sends status updates to GUI.
    For example log messages into TMemo and percentage into Gauge.

    It would be nice to de-couple status variables from the calculating thread, but then the queue may contain several calls with different values of which only last would matter.

    For example, GUI was busy and now enquede among others are:
    UpdateStatus (10%)
    UpdateStatus (20%)
    UpdateStatus (30%)

    Of those obviously only last should be called now.

    Of course, any random calls should not be blindly aggregated. But some surely must.

    ReplyDelete
  5. @Arioch, not at the moment. I have some similar ideas but they are all based on a priority queue which I haven't written yet.

    ReplyDelete