Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing value to synchronize thread

I'm new to thread, so i've been trying with this for hours (i'm using XE4),

i have a simple thread

type
  TSendThread = class(TThread)
  private
  public
    procedure proc(const s : string);
  protected
    procedure Execute; override;
  end;

  procedure TSendThread.proc(const S: String);
  begin
    showmessage(s);
  end;

Now, in my main form, i want to call that "proc" with :

procedure TForm1.Button1Click(Sender: TObject);
var
  t : TSendThread;
begin
    t := TSendThread.create(true);
    t.Synchronize(nil, t.proc('foo'));
end;

But whenever i try t compile that i get :

There is no overloaded version of 'Synchronize' that can be called with these arguments

that does not make sense (to me) because when i remove the "S" parameter from "proc" it works fine.

like image 989
Ouerghi Yassine Avatar asked Jun 01 '13 07:06

Ouerghi Yassine


2 Answers

Look at the various declarations of TThread.Synchronize(). You are trying to call the version that takes a TThreadMethod as input. TThreadMethod is parameter-less:

TThreadMethod = procedure of object;

That is why passing just t.Proc works but passing t.Proc('foo') does not.

With that said, you are completely misusing TThread.Synchronize(). You don't need to create a TThread object in order to use the static version of Synchronize(). And if you do create a TThread object, make it actually do something, like this:

type
  TSendThread = class(TThread)
  public
    fStr: String;
    procedure DoProc;
    procedure Proc(const S: string);
  protected
    procedure Execute; override;
  end;

  procedure TSendThread.Execute;
  begin
    Proc('foo');
  end;

  procedure TSendThread.Proc(const S: string);
  begin
    fStr := S;
    Synchronize(DoProc);
  end;

  procedure TSendThread.DoProc;
  begin
    ShowMessage(fStr);
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  t : TSendThread;
begin
  t := TSendThread.Create(False);
  t.WaitFor;
  t.Free;
end;

However, because you are using XE4, Synchronize() also supports anonymous procedures as well, which would eliminate your TSendThread class completely in this example, eg:

procedure TForm1.Button1Click(Sender: TObject);
begin
  TThread.Synchronize(nil,
    procedure
    begin
      ShowMessage('foo');
    end
  );
end;

Update: given new info about what you REALLY want to do with your thread, you need to go about it like this instead:

type
  TSendThread = class(TThread)
  private
    fURL, fMethod, fParam: string;
  protected
    procedure Execute; override;
  public
    constructor Create(aURL, aMethod, aParam: string);
  end;

constructor TSendThread.Create(aURL, aMethod, aParam: string);
begin
  inherited Create(False);
  fURL := aUrl;
  fMethod := aMethod;
  fParam := aParam;
end;

procedure TSendThread.Execute;
begin
  // use fURL, fMethod, and fParam as needed...
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  t : TSendThread;
begin
  t := TSendThread.Create('url', 'method', 'param');
  ...
end;

Or like this:

type
  TSendThread = class(TThread)
  private
    fURL, fMethod, fParam: string;
    procedure GetValues;
  protected
    procedure Execute; override;
  end;

procedure TSendThread.GetValues;
begin
  fURL := ...;
  fMethod := ...;
  fParam := ...;
end;

procedure TSendThread.Execute;
begin
  Synchronize(GetValues);
  // use fURL, fMethod, and fParam as needed...
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  t : TSendThread;
begin
  t := TSendThread.Create(False);
  ...
end;
like image 79
Remy Lebeau Avatar answered Oct 05 '22 10:10

Remy Lebeau


Synchronize only takes a parameterless procedure, as I'm sure you've figured out. That means you have to use properties you get from the main thread in order to do certain things with it. For instance, my thread object is named monitor:

Synchronize(UpdateCaption);  // as called in the thread code.

procedure monitor.UpdateCaption;
// synchronize procedure for monitor thread - updates memo on form.
begin
  With Form1.CommandText.Lines do
    Add(TextString);
end;

Alternatively, you pass messages to the main thread, but this is a quick in a pinch way to do it.

like image 36
Glenn1234 Avatar answered Oct 05 '22 08:10

Glenn1234