Проблема с потоками в Delphi - PullRequest
4 голосов
/ 01 августа 2011

У меня проблема с потоками в 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;

Ответы [ 5 ]

3 голосов
/ 01 августа 2011

Никто не указал на это, внутри функции не было возвращено значение.

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 голос
/ 10 мая 2017

Об ожидании

Как правильно отметили люди, вам не следует называть "Self.WaitFor;".

WaitFor предназначен для вызова из других потоков. Нить может не дождаться себя - это противоречит логике. Например, я не могу ждать себя - я всегда готов к себе! ;-) Такова тема.

Лучший способ закрыть форму из потока

Лучший способ закрыть форму - это отправить сообщение WM_CLOSE его дескриптору окна, используя PostMessage.

Вместо «Синхронизировать (DoSync)»; выполните следующее: «PostMessage (FormProgress.Handle, WM_CLOSE, 0, 0);».

FormProgress здесь - это переменная, которая содержит указатель на экземпляр класса TFormProgress. Следовательно, DoSync не нужен.

При синхронизации

Как правило, «Синхронизация» показывает, что что-то плохое в дизайне приложения. Лучше разрабатывать приложения вообще без синхронизации.

1 голос
/ 01 августа 2011

В коде, который вы разместили, 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;
0 голосов
/ 01 августа 2011

Это - хорошая документация по многопоточности в Delphi, с примерами, ситуациями.Начните читать с самого начала, и я уверен, что вы найдете ответ самостоятельно.Вам не нужно читать все, только первые 4-5 глав.

0 голосов
/ 01 августа 2011

Мое предположение: форма открывается в модальном режиме (form.ShowModal), и есть что-то, что назначает form.ModalResult до завершения расчета.Это может привести к закрытию istantaneus формы.

Может быть, вы поместили TBitButton, в котором для свойства modalresult установлено значение mrOk?если вы это сделали, нажатие этой кнопки закроет форму, как только завершится обработчик события onClick, независимо от того, есть ли запущенный поток.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...