Question

When creating a thread object, I want to call code from the application that needs to be synchronized. The problem is that I don't know how to call Synchronize for an application function with parameters.

Say we have

procedure ThreadObject.Execute;
var
  val1,val2:integer;
  Star:string;
begin
  Synchronize(funcyfunc); //how to pass val1,val2,star here?
end;

where funcyfunc is defined as follow

procedure OtherClass.funcyfunc(param1,param2:integer;spok:string);
begin
   letsCallFriends(spok,param1);
   letsCallFriends(spok,param2);
end;

now the odd solution to this would be to say in ThreadObject private

private
  star:string;
  val1,val2:integer;
  procedure starVal;

and in the implementation we do

procedure ThreadObject.starVal;
begin
  funcyfunc(Star,val1,val2);
end;

and in the thread execute we change to

procedure ThreadObject.Execute;
var
  val1,val2:integer;
  Star:string;
begin
  Synchronize(starVal); //how to pass val1,val2,star here?
end;

but this is a hassle, as for each procedure call there must be a global variable. Is there a better way?

code:

unit ThreadObject;

interface

uses
  Classes;

type
  TThreadObject= class(TThread)
  private
    star:string;
    val1,val2:integer;
    procedure starVal;
  protected
    procedure Execute; override;

    //assume we have a constructor that ini the star val1 val2.
  end;

implementation

{ TThreadObject }

procedure ThreadObject.Execute;
var
  val1,val2:integer;
  Star:string;
begin
  Synchronize(starVal); //how to pass val1,val2,star here?
end;

procedure ThreadObject.starVal;
begin
  funcyfunc(Star,val1,val2);
end;

end.
Was it helpful?

Solution

Use anonymous methods.

As you can read in the manual for the TThread.Synchronize

Synchronize(
  procedure
  begin
    Form1.Memo1.Lines.Add('Begin Execution');
  end);

In the example above the referenced variable Form1 would kind of like be copied and saved until the procedure gets executed (that is called variable capture).

Note: David objects to the idea of "copied variable" and he probably is right. However discussing all the corner cases and implementation details would be an overkill. His comparison to "global variable" OTOH would probably have troubles with recursive procedures, etc. All the simple to grasp analogies are very rough and tilted one way or another ISTM.

Your anonymous procedure should use your variables val1 and val2 and they then should get captured too

http://docwiki.embarcadero.com/Libraries/XE5/en/System.Classes.TThread.Synchronize

OTHER TIPS

If you're using an older version of Delphi that doesn't support anonymous methods, you make your "parameters" fields on your class. I.e.

procedure ThreadObject.Execute;
var
  val1,val2:integer;
  Star:string;
begin
  FVal1 := val1;
  FVal2 := val2;
  FStar := Star;
  Synchronize(funcyfunc);
end;

procedure ThreadObject.FuncyFunc;
begin
  //Do stuff with FVal1, FVal2 and FStar
end;

Note these are not global.
It is also quite safe because the point of Synchronize is to ensure that two threads co-ordinate with each other. So, provided you don't have other threads trying to access the same data, you won't have any race conditions.

Yes, it is a little "klunky", but that's the advantage of using anonymous methods in newer versions of Delphi.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top