【问题标题】:Passing value to synchronize thread传递值以同步线程
【发布时间】:2013-06-01 07:46:05
【问题描述】:

我是线程新手,所以我已经尝试了几个小时(我正在使用 XE4),

我有一个简单的线程

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;

现在,在我的主要形式中,我想用以下方式调用“proc”:

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

但是每当我尝试编译时,我都会得到:

没有可以调用的“同步”的重载版本 有了这些论据

这没有意义(对我来说),因为当我从“proc”中删除“S”参数时它工作正常。

【问题讨论】:

  • 首先,Synchronize 用于访问例如来自工人的主线程。不要在主线程中调用Synchronize
  • 嗯,这是我在向线程发送某些东西时发现的唯一方法(不使用创建过程并且没有“SendMessage”东西),无论如何都可以将值发送到线程并使用传递的值?
  • 嗯,这是一个不同且相当复杂的主题。我敢肯定,如果你问一个问题,描述你想在你的(正在运行的?)工作线程中更改哪些 数据,有人会给你一个复杂的答案。
  • 嗯,我只是想线程化 Indy IdHTTP,我想向线程发送 3 个参数(URL、GET/POST、lParam)。我想我可以只调用 Synchronize 方法...
  • @TLama:在主线程中调用Synchronize() 是完全安全的。它会立即执行指定的过程。这对于不知道是在主线程还是工作线程中调用的代码很有用。

标签: multithreading delphi


【解决方案1】:

查看TThread.Synchronize() 的各种声明。您正在尝试调用将 TThreadMethod 作为输入的版本。 TThreadMethod 是无参数的:

TThreadMethod = procedure of object;

这就是为什么只传递t.Proc 有效而传递t.Proc('foo') 无效。

话虽如此,您完全滥用了TThread.Synchronize()。您无需创建TThread 对象即可使用Synchronize() 的静态版本。如果你确实创建了一个TThread 对象,让它真正做一些事情,像这样:

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;

但是,由于您使用的是 XE4,Synchronize() 也支持匿名过程,这将在此示例中完全消除您的 TSendThread 类,例如:

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

更新:给出关于你真正想用你的线程做什么的新信息,你需要这样去做:

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;

或者像这样:

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;

【讨论】:

  • 那么一个线程可以不用创建就可以使用吗?正如我在上面的评论中所说,我想从 Button1Click 发送那个“foo”,而不使用“Create”。能做到吗?
  • 不,我说Synchronize()可以在不创建线程对象的情况下使用。那是因为Synchronize() 有几个重载版本,其中有几个被声明为static
【解决方案2】:

Synchronize 只需要一个无参数的过程,我相信您已经知道了。这意味着您必须使用从主线程获得的属性才能用它做某些事情。例如,我的线程对象被命名为监视器:

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;

或者,您将消息传递给主线程,但这是一种快速的方法。

【讨论】:

    【解决方案3】:

    另一种方法是编写一个不带参数的包装函数,并在Synchronize() 中调用这个无参数方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多