Могу ли я переместить Delphi TThread.Synchronize() локально в форму VCL, которая будет вызываться из основного или рабочего потока?

Я использую CreateAnonymousThread для рабочей задачи, и когда я начал с ней, я использовал Synchronize во всей декларации в соответствии с документированными примерами, например:

procedure Txxx.RunWorker;
begin
     FExecutionThread := TThread.CreateAnonymousThread(procedure ()
     begin

        TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
            // Here before worker stuff
            NotifyBeforeWorkerStuff; 

          end);

        // Do worker stuff

        TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
            // Here after worker stuff
            NotifyAfterWorkerStuff;
          end);
      end);

      FExecutionThread.Start;
    end;
end;

Как вы видите, из этого потока я запускаю уведомления о событиях для различных частей моего приложения, включая формы VCL (NotifyBeforeWorkerStuff и т. Д.). Позже я увидел, что мог бы перемещать Synchronize() более локально к каждой форме VCL близко к точке, которая фактически требовала ее для обновления (небезопасных) элементов управления VCL:

    procedure TSomeVCLForm.ReceiveNotification;
    begin
      TThread.Synchronize (TThread.CurrentThread,
          procedure ()
          begin
            Label1.Caption := GetSomeStringFunction;
          end);
     end;

Рабочий поток становится проще, если я живу с уведомлениями из основного или рабочего потоков:

   procedure Txxx.RunWorker;
   begin
     FExecutionThread := TThread.CreateAnonymousThread(procedure ()
       begin

         NotifyBeforeWorkerStuff; 

         // Do worker stuff

         NotifyAfterWorkerStuff;

       end);

     FExecutionThread.Start;
   end;

У меня есть несколько вопросов о том, правильно ли это:

  1. Мои уведомления могут быть из рабочего потока, но также из основного потока (например, полученные из нажатия кнопки). Итак, когда "ReceiveNotification" в форме VCL вызывается из основного потока, разрешается ли вызывать TThread.Synchronize, как указано выше? Документы XE8 не подразумевают, но проверяют System.Classes, это выглядит нормально и работает нормально.
  2. Внутри "ReceiveNotification", когда Label1.Caption выбирает строку из GetSomeStringFunction, верно ли, что нет абсолютно никакой необходимости в блокировке внутри этой функции, даже если вызов выполняется из рабочего потока?

Спасибо за любой совет.

1 ответ

Решение

В документации сказано:

Предупреждение: не вызывайте Synchronize из основного потока. Это может вызвать бесконечный цикл.

Я думаю, что документация просто неверна. Реализация в XE8 проверяет, является ли текущий поток основным потоком. Если это так, то метод выполняется напрямую.

Блокировка не требуется в ReceiveNotification потому что призыв к GetSomeStringFunction всегда выполняется в главном потоке.

Другие вопросы по тегам