【问题标题】:Problem with threads in DelphiDelphi中的线程问题
【发布时间】:2021-08-16 22:14:21
【问题描述】:

我在 Delphi 中遇到了线程问题。当使用 TIdHashMessageDigest5 从大文件中获取 MD5 时,我注意到它花费了太多时间,并最终导致应用程序冻结。

我正在考虑使用单独的线程。所以我做了一个小表格,在其中插入一个简单的消息、一个按钮和一个 pbstMarquee 样式的进度条。我在这个表单的 show 事件上启动了一个线程。

我的问题是:我想在 HashStreamAsHex 读取成功后关闭这个表单,但是我该怎么做呢?我尝试在同步时调用 Close 方法,但随后窗体在不等待该线程完成的情况下关闭。我也试过用waitfor方法,没有成功。

有人可以帮我解决这个问题,给我一些例子,或者链接或类似的东西吗?

非常感谢,抱歉我的英语不好。

About form:
-----------
procedure TFormProgress.FormProgressOnShow(Sender: TObject);
begin
  ProgressThread := TProgressThread.Create(True);
  ProgressThread.Form := FormProgress;
  ProgressThread.FileSrc := uFileSrc;
  ProgressThread.Start;
end;

About thread:
-------------
procedure TProgressThread.Execute;
begin
  FreeOnTerminate := True;
  uFileMD5 := GetFileMd5 (uFileSrc)  // function is definited in other unit.
  Self.WaitFor;
  Synchronize(DoSync);
end;

procedure TProgressThread.DoSync;
begin
  oForm.Close;
end;

GetFileMd5 è so defined:

function GetFileMD5(const Src: TFileName): UnicodeString;
var
  Md5: TIdHashMessageDigest5;
  FileSrc: TFileStream;
  StrMd5: UnicodeString;
begin
  Md5 := TIdHashMessageDigest5.Create;
  try
    FileSrc := TFileStream.Create(Src, fmOpenRead);
    try
      StrMd5 := Md5.HashStreamAsHex(FileSrc);
    finally
      FileSrc.Free;
    end;
  finally
    Md5.Free;
  end;
end;

【问题讨论】:

  • 你好,表单是模态表单,但是当 HashStreamAsHex 方法返回文件的 md5 时,我需要关闭表单。这个方法è在一个线程中调用。对于大文件实际上需要几分钟并冻结。
  • 可以告诉我正确显示带有缩进的delphi代码吗?如您所见,我有一些问题:(我错在哪里?非常感谢。
  • 选择代码块并按下{}按钮
  • 请原谅,{} 按钮在哪里?我已经搜索了所有页面但没有找到:(
  • 编辑代码时,编辑框上方有一个按钮工具栏。点击看起来像 {} 的那个

标签: multithreading delphi md5


【解决方案1】:

没有人指出这一点,函数内部没有返回值。

function GetFileMD5(const Src: TFileName): UnicodeString;
var
  Md5: TIdHashMessageDigest5;
  FileSrc: TFileStream;
  StrMd5: UnicodeString;
begin
  Md5 := TIdHashMessageDigest5.Create;
  try
    FileSrc := TFileStream.Create(Src, fmOpenRead);
    try
      StrMd5 := Md5.HashStreamAsHex(FileSrc);
    finally
      FileSrc.Free;
    end;
  finally
    Md5.Free;
  end;
  // You are missing this line, calculated md5 was never returned
  Result := StrMd5;
end;

【讨论】:

  • +1 抱歉,我在用相同的观察结果更新自己的答案后看到了这个答案。
【解决方案2】:

在您发布的代码中,Self.WaitFor 将永远不会返回。等到线程终止,即它的Execute 方法已经完成。但这不可能发生,因为它会停下来等待自己。您应该简单地删除对WaitFor 的调用。

我也想知道Close 是否是终止表单的正确方法。如果它真的是一个模态形式,那么你应该使用oForm.ModalResult := mrOK


我刚刚看到您的编辑,其中包括GetFileMD5 的定义。此函数不返回值。您应该会收到一个编译器警告,告诉您这一点——阅读编译器警告,它们非常有价值。像这样写GetFileMD5

function GetFileMD5(const Src: TFileName): string;
var
  Md5: TIdHashMessageDigest5;
  FileSrc: TFileStream;
begin
  Md5 := TIdHashMessageDigest5.Create;
  try
    FileSrc := TFileStream.Create(Src, fmOpenRead);
    try
      Result := Md5.HashStreamAsHex(FileSrc);
    finally
      FileSrc.Free;
    end;
  finally
    Md5.Free;
  end;
end;

【讨论】:

  • 我已经尝试过,但是没有,当我运行应用程序时,表单也会在不到一秒的时间内关闭,文件最大并且 uFileMD5 不返回文件的 md5(当然,如果我只运行它正常工作)。我做什么?
  • 当您单步执行TProgressThread.Execute 时会发生什么? GetFileMd5 返回什么?
  • 完成但什么也没做,每隔不到一秒就关闭表单,好像没有执行获取 md5 的函数 :( 有什么想法?
  • 单步执行 TProgressThread.Execute 时会发生什么? GetFileMd5 返回什么?你知道如何使用调试器吗?
  • 我的猜测是 MD5 计算工作正常。我认为即使是典型的大文件也应该很快。
【解决方案3】:

我的猜测:表单以模态模式(form.ShowModal)打开,并且在计算完成之前分配了 form.ModalResult 。 这会导致表单的 isstananeus 关闭。

也许您是否放置了一个将 modalresult 属性设置为 mrOk 的 TBitButton?如果你已经这样做了,按下该按钮将在 onClick 事件处理程序终止后立即关闭表单,无论是否有正在运行的线程。

【讨论】:

    【解决方案4】:

    This is 是一个很好的关于 delphi 线程的文档,有例子,情况。从头开始阅读,相信你会自己找到答案。您不必阅读所有内容,只需阅读前 4-5 章即可。

    【讨论】:

    • 该链接不再有效,它表明该域正在出售。请考虑更新或删除该链接,因为它目前显示的广告与该主题无关。
    • @MaximMasiutin:感谢您的报告,找到了一个有效的链接。
    【解决方案5】:

    关于等待

    正如人们正确指出的那样,您不应该调用“Self.WaitFor;”。

    “WaitFor”被设计为从其他线程调用。线程可能不会等待自己——这与逻辑相反。例如,我不能等待自己——我总是为自己做好准备! ;-) 线程也是如此。

    从线程关闭表单的最佳方法

    关闭表单的最佳方法是使用“PostMessage”向其窗口句柄发送“WM_CLOSE”消息。

    而不是“Synchronize(DoSync);”执行以下操作:“PostMessage(FormProgress.Handle, WM_CLOSE, 0, 0);”。

    这里的“FormProgress”是保存指向“TFormProgress”类实例的指针的变量。因此,不需要“DoSync”。

    同步时

    通常,“同步”表明应用程序设计存在问题。最好设计完全没有任何“同步”的应用程序。

    【讨论】:

      猜你喜欢
      • 2021-01-15
      • 1970-01-01
      • 1970-01-01
      • 2020-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-29
      • 1970-01-01
      相关资源
      最近更新 更多