Delphi.Как узнать, сигнализируется ли TEvent или нет? - PullRequest
1 голос
/ 06 июня 2011

скажите, пожалуйста: как узнать, сигнализируется ли TEvent или нет?

Нажмите кнопку STOP = SetEvent(Events[1]);

Я пытаюсь разархивировать архив, и если кнопка STOPПосле нажатия кнопки протектор должен быть прерван, а разархивирование должно быть прервано.

Мой код:

procedure TForm2.ZipForge1OverallProgress(Sender: TObject; Progress: Double;
  Operation: TZFProcessOperation; ProgressPhase: TZFProgressPhase;
  var Cancel: Boolean);
begin
  if Events[1]<>null then
  begin
    ThreadUpdating.Terminate;
    Abort;
  end else
    form2.Update_ProgressBar.Position := Trunc(Progress);
end;

Но если я нажимаю кнопку STOP (SetEvent (Events [1])), ничего не происходит,

PS: я использую WaitForMultipleObjects(Event[1],Event[2]) в теме.Событие [1] используется в качестве сигнала STOP в двух частях: в ZipForge1OverallProgress и WaitForMultipleObjects.

Ответы [ 2 ]

3 голосов
/ 06 июня 2011

Звоните WaitForMultipleObjects, но делайте это правильно. Вы не показали этот код, и код, который вы показали, все равно выглядит неправильно.

Во-первых, похоже, что вы пытаетесь проверить, является ли элемент Events[1] нулевым указателем. Нулевые указатели в Delphi пишутся nil, а не null; последний - функция , которая возвращает нулевое Variant значение (но поскольку Variant можно преобразовать во множество других типов, компилятор, вероятно, не предупредит вас о том, что ваш код неправильно). Затем выглядит так, как будто событие, которое вы обрабатываете, имеет параметр Cancel, который вы можете установить, чтобы уведомить вызывающего абонента о том, что он должен прекратить то, что он делает, но вместо того, чтобы просто установить это, вы бросаете EAbort исключение.

Если событие прогресса, которое вы здесь показываете, действительно выполняется в отдельном потоке, то оно не должно изменять свойства объектов VCL, таких как TProgressBar. Вам нужно использовать Synchronize, чтобы убедиться, что операции VCL выполняются только в потоке VCL.

Как я уже сказал, вам нужно позвонить WaitForMultipleObjects собственности. Это означает передачу четырех параметров, с одной стороны. Похоже, у вас есть массив по крайней мере с двумя дескрипторами, поэтому назовите его так:

var
  Ret: DWord;

Ret := WaitForMultipleObjects(2, @Events[1], False, Timeout);
case Ret of
  Wait_Object_0: begin
    // Events[1] is signaled
  end;
  Wait_Object_0 + 1: begin
    // Events[2] is signaled
  end;
  Wait_Timeout: begin
    // Neither is signaled. Do some more work, or go back to waiting.
  end;
  Wait_Failed: begin
    RaiseLastOSError;
  end;
end;

Если все, что вы хотите сделать, это проверить , есть ли сигнал о ручке, но вы не хотите ждать , пока он не будет сигнализирован, если это не так, тогда используйте значение времени ожидания ноль.

1 голос
/ 06 июня 2011

'if Events [1] <> null then begin' это псевдокод?Мне это не нравится - для меня это больше похоже на настоящий Delphi :) Если это так, вы просто проверяете, назначен ли объект Event, а не сигнализирован.

Если вы хотите опросить событие stopв вашем обработчике TotalProgress вам нужно вызывать WaitForSingleObject () с таймаутом 0.

Не можете ли вы просто проверить логическое значение «stop» в вашем обработчике?Это было бы намного быстрее, чем вызов ядра.Вам может также потребоваться Событие, чтобы вызов WFMO в верхней части потока получал сигнал, когда требуется прерывание / завершение, или вам может потребоваться сигнализировать о каком-либо другом событии в массиве WFMO, всегда проверяя остановку:

TmyThread = class(TThread)
..
public
  stopRequested:boolean;
  procedure stop;
  ..
end;

procedure TmyThread.stop;
begin
  stopRequested:=true;
  someEventInWFMOarray.signal;
end;

procedure TmyThread.execute;
begin;
  while true do
  begin
    waitForMultipeObjects();
    if stopRequested then exit;
    work;
  end;
end;

TForm2.ZipForge1OverallProgress(sender:TObject,......)
begin
  cancel:=TmyThread(Sender).stopRequested;
  if cancel then exit;
  doStuff; 
end;
...