Опасно ли использовать синхронизацию в приложении, отличном от VCL?
Если код Delphi был написан с синхронизацией для сериализации доступа к основному потоку VCL, но этот код затем используется в приложении, отличном от VCL, будет ли он синхронизироваться с основным потоком приложения или просто не имеет никакого эффекта вообще?
Пример:
procedure TMyThread.Execute;
begin
// ... other code
Synchronize(SomeMethod);
// ...
end;
Предположим, что
- это приложение, отличное от VCL, которое имеет основной поток, который выполняется в бесконечном цикле (или до его завершения)
- основной поток не вызывает
CheckSynchronize
напрямую или в обработчике WakeMainThread
- выполняется вторичный поток и выполняет синхронизацию (SomeMethod), как в приведенном выше примере
Будет ли винт зависать на линии Synchronize (SomeMethod)?
Ответы
Ответ 1
TThread
предоставляет средства для программ, отличных от VCL, для проверки очереди синхронизации, поэтому они могут продолжать использовать многопоточные библиотеки, которые ожидают синхронизации своих методов. Это описано в документации для CheckSynchronize
. Помните, что это задание приложения для проверки очереди, а не вашей библиотеки.
Пока приложение выполняет свою часть контракта, ваше использование Synchronize
должно быть прекрасным. Если это не так, то ваша программа будет работать некорректно, но я не знаю, какие именно симптомы следует ожидать. Висячие, безусловно, звучат правдоподобно.
Ответ 2
Возможно ли использовать синхронизацию в приложении, отличном от VCL?
Да, это опасно. Если ваш основной поток не вызывает CheckSynchronize
, тогда Synchronize
приведет к тупиковой ситуации.
Предположим, что
- это приложение, отличное от VCL, которое имеет основной поток, который выполняется в бесконечном цикле (или до его завершения)
- основной поток не вызывает
CheckSynchronize
напрямую или в обработчике WakeMainThread
- выполняется вторичный поток и выполняется
Synchronize(SomeMethod)
, как в приведенном выше примере
Будет ли винт зависать на линии Synchronize(SomeMethod)
?
Вызов Synchronize
блокирует фоновый поток, пока основной поток не вызовет CheckSynchronize
. Итак, если основной поток никогда не вызывает CheckSynchronize
, фоновый поток будет блокироваться бесконечно.
Следующая программа иллюстрирует это:
program TheBigSleep;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, Windows;
type
TMyThread = class(TThread)
protected
procedure Execute; override;
end;
procedure TMyThread.Execute;
begin
Synchronize(SysUtils.Beep);
end;
begin
with TMyThread.Create do
WaitForSingleObject(Handle, INFINITE);
//don't call WaitFor since that, in turn, calls CheckSynchronize
end.
Ответ 3
Поскольку вы помещаете код Delphi в библиотеку для использования другими приложениями, я бы не советовал использовать Synchronize()
вообще, так как в потоке нет понятия о том, что происходит вне себя. Лучший выбор заключается в том, чтобы поток показывал событие обратного вызова, которое поток может вызывать в своем собственном контексте, когда это необходимо, а затем позволяет приложению предоставлять обработчик функции обратного вызова, который решает наилучший способ синхронизации с основным потоком приложения при необходимости.