【问题标题】:BeginThread Structure - DelphiBeginThread 结构 - Delphi
【发布时间】:2011-06-14 21:51:12
【问题描述】:

我现在有一个几乎完成的应用程序,我要实现的下一个功能是线程。我选择使用 BeginThread(),尽管我知道 delphi 中的 TThread。我遇到的问题是 BeginThread() 调用的结构。通常,程序中将调用我想要线程化的函数的行是

CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);

op 是一个整数。

我已将其切换为从中创建线程的行是

BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x);

从我能找到的关于如何实际使用 BeginThread() 的少量信息中,这应该是一个很好的调用,但是在编译时,我得到的只是关于 BeginThread() 语句参数结构的编译器错误。

编辑信息。

当前调用 CompareFiles 的过程是

procedure TForm1.Panel29Click(Sender: TObject);
var
op,x : integer;

begin
    if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then
        begin
          op := 3;
          if RadioButton7.Checked = True then op := 0;
          if RadioButton3.Checked = True then op := 1;
          if RadioButton4.Checked = True then op := 2;
          if RadioButton5.Checked = True then op := 3;
          if RadioButton6.Checked = True then op := 4;
          CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op);
        end;
end;

如果我按照几个人的建议使用 TThread,如下面的 Rob 所示,我对如何将 op、Edit3/4.Text 和 StringGrid2 传递给 CompareFiles 感到困惑。从我见过的 TThread 示例中猜测,我想我会将上面的代码替换为 TCompareFilesThread.Execute 并将 Panel29Click 中的当前代码放入 TCompareFilesThread.Create 然后添加

FEdit3Text := Edit3Text;
FEdit4Text := Edit4Text;
FGrid := Grid;

到这里

FEdit3Text := Form1.Edit3.Text;
FEdit4Text := Form1.Edit4.Text;
FGrid := Form1.StringGrid2;

但我有这种烦人的感觉,完全不合时宜。

【问题讨论】:

  • “关于事物不匹配的投诉”不是一个很有用的描述。您能否编辑您的问题并将错误消息的副本粘贴到其中?
  • 我也很好奇你为什么选择使用TThread?在没有良好对象封装的情况下使用全局线程函数会使与并发和竞争条件相关的事情变得非常复杂。我也很好奇为什么您即将完成应用程序然后决定添加线程。 IMO,应该从一开始就考虑线程,而不是事后考虑。如果不及早考虑到,很有可能会穿过地雷。
  • 现在实现线程的原因是这对我来说是一个学习应用程序。线程一直是计划好的,现在应用程序的核心功能已经完成(大部分),只是为了实现它。至于 TThread,我似乎找不到很好的解释来说明如何使用它。
  • 我在这里开始学习使用 Delphi 进行线程处理:eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/ToC.html 也许对您来说也是一个好的开始?
  • 不要不要自己调用Execute 方法。线程会自动调用它。如果您自己调用它,您将从主线程调用它,此时您将失去在单独线程中运行的所有优势。请考虑为您的表单和控件提供有意义的名称。您的计算机选择了您现在拥有的名称,它们很糟糕。您是人类,而且您知道得更多,因此请根据他们所做的而不是根据您碰巧将它们放在表格上的顺序来控制并命名它们。

标签: multithreading delphi beginthread


【解决方案1】:

根本不是使用BeginThread的方式。该函数需要一个指向带有 one 参数的函数的指针,但您尝试调用的函数需要四个。您为BeginThread 提供的一个参数是一个字符串,以便将其转发到线程过程,但您显然希望某种魔法能够将该字符串转换为这些变量包含的值。

这不是 Delphi 的工作方式,即使对于 可以 执行类似操作的语言,通常也不鼓励实际执行

要将多个参数传递给BeginThread,请使用您需要的所有值定义一条记录,并定义一个记录指针:

type
  PCompareFilesParams = ^TCompareFilesParams;
  TCompareFilesParams = record
    Edit3Text,
    Edit4Text: string;
    Grid: TStringGrid;
    Op: Integer;
  end;

更改CompareFiles 以接受指向该记录的指针:

function CompareFiles(Params: PCompareFilesParams): Integer;

要启动线程,您需要分配该记录的一个实例并填充其字段:

var
  Params: PCompareFilesParams;
begin
  New(Params);
  Params.Edit3Text := Edit3.Text;
  Params.Edit4Text := Edit4.Text;
  Params.Grid := StringGrid2;
  Params.Op := op;
  BeginThread(nil, 0, @CompareFiles, Params, 0, x);

像这样实现CompareFiles,以便在线程终止之前释放记录:

function CompareFiles(Params: PCompareFilesParams): Integer;
begin
  try
    // <Normal implementation goes here.>
  finally
    Dispose(Params);
  end;
end;

不过,如果您只使用TThread,就可以让这一切变得更容易。您可以让您的后代类在其构造函数中具有任意数量的参数,因此您不必为动态分配和释放特殊记录而烦恼。

type
  TCompareFilesThread = class(TThread)
  private
    FEdit3Text,
    FEdit4Text: string;
    FGrid: TStringGrid;
    FOp: Integer;
    procedure Execute; override;
  public
    constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer);
    property ReturnValue;
  end;

constructor TCompareFilesThread.Create;
begin
  inherited Create(False);
  FEdit3Text := Edit3Text;
  FEdit4Text := Edit4Text;
  FGrid := Grid;
  FOp := Op;
end;

procedure TCompareFilesThread.Execute;
begin
  ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp);
end;

您无需调用BeginThread,而是实例化该类并让它运行:

var
  ThreadRef: TThread;


ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op);

使用线程还有更多内容,例如知道线程何时完成运行,但我认为您已经足够开始了。不过,最后要注意的一件事是TStringGrid 是一个 VCL 控件。你不能从你创建的这个新线程中对它做任何事情(不管你最终如何创建它)。您对网格控件所做的一切都需要从主线程中完成。使用TThread.SynchronizeTThread.Queue 将任何VCL 操作转移到主线程上。您的文件比较线程将等待同步操作完成,但它会继续运行而不等待排队操作完成。

【讨论】:

  • +1 的精彩解释!但是“删除(参数);”应该是“处置(参数);”
  • @Arthurprs 哎呀!你能告诉我我整天都在用 C++ 吗?
  • 如果我能弄清楚如何使用 TThread,那么我会的。例如,使用您那里的示例代码,我将在 OnClick 过程中调用什么/如何调用它,它设置 op 并决定何时运行 CompareFiles。
  • 更新了原始帖子,提供了有关先前评论的更多信息。
  • @TheFlatline:TThread 非常易于使用,并且有大量关于如何使用的教程。只需从TThread 继承,创建一个构造函数,在线程中获取您需要的所有内容并覆盖受保护的Execute 方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多