Вызов TThread.Synchronize в основном потоке

Воровство из статьи Уве Раабе Синхронизировать и поставить в очередь с Параметры Я делаю так:

if GetCurrentThreadID = MainThreadID then
  FDataLogger(IntToStr(lNrItems) + ' elements:')
else
  TThread.Synchronize(nil,
          procedure
          begin
            FDataLogger(IntToStr(lNrItems) + ' elements:');
          end);

Но если я просто

  TThread.Synchronize(nil,
          procedure
          begin
            FDataLogger(IntToStr(lNrItems) + ' elements:');
          end);

это тоже работает.

Поскольку первая конструкция приводит к большему объему кода, много ли пользы от выделения основного потока?


person Jan Doggen    schedule 18.03.2020    source источник
comment
Кстати, приведенный выше код, скорее всего, содержит другую ошибку. Если lNrItems = 1, это говорит о 1 элементе, что грамматически неверно. Самое простое (и, возможно, лучшее) решение — написать element(s) в строковых литералах.   -  person Andreas Rejbrand    schedule 18.03.2020
comment
@AndreasRejbrand Это просто журналы отладки ;-)   -  person Jan Doggen    schedule 18.03.2020


Ответы (2)


Хотя документация предупреждает вас об этом, фактический код внутри TThread.Synchronize похож на показанный код оболочки. Так что я почти уверен, что вы можете обойтись более короткой версией.

Возможно, я также был введен в заблуждение документацией (или в древние времена, возможно, был укушен таким поведением в Delphi 5 или около того), когда писал эту статью.

person Uwe Raabe    schedule 18.03.2020
comment
Ну, фактическая реализация, возможно, не имеет значения. Если в документации сказано, что метод нельзя использовать в основном потоке, возможно, вы не должны использовать его в основном потоке. Даже если вам это сойдет с рук сегодня, Embarcadero может изменить реализацию в будущем, поскольку они могут предположить, что все достойные разработчики следуют контракту, указанному в документации. Только если Embarcadero изменит документацию, чтобы разрешить это, это будет безопасно, потому что тогда Embarcadero обещает, что это безопасно и останется таковым. - person Andreas Rejbrand; 18.03.2020
comment
@AndreasRejbrand, я понимаю твою точку зрения, и, конечно же, ты прав. Просто проверка кода для нескольких версий Delphi до Delphi 7 показала, что это должно быть безопасно. Это было только в Delphi 5, который действует в соответствии с документацией (на данный момент я не могу сказать для Delphi 6). Я был бы весьма удивлен, если бы Embarcadero (или кто бы там ни был, кто будет за это отвечать) начнет возвращать текущее поведение к чему-то из каменного века Delphi. - person Uwe Raabe; 18.03.2020
comment
@UweRaabe даже в Delphi 5 и более ранних версиях (реализация была изменена в Delphi 6) вызов Synchronize() в основном потоке был по-прежнему безопасным. Синхронизация выполнялась самой Windows, а не RTL, но она по-прежнему учитывала потоки и просто выполняла пользовательскую процедуру напрямую, если она вызывалась в основном потоке. - person Remy Lebeau; 18.03.2020

В документации TThread.Synchronize четко сказано:

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

http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TThread.Synchronize

person zed    schedule 18.03.2020
comment
Я думаю, что в документации есть ошибка. Начиная с Delphi XE8, поддерживается вызов Synchronize из основного потока. См. stackoverflow.com/a/29919480/576719. - person LU RD; 18.03.2020
comment
Предупреждение в документации неверно и всегда было неверным. Вызов Synchronize() в основном потоке всегда был безопасным, начиная с самого начала Synchronize(). - person Remy Lebeau; 18.03.2020