2012-05-21 2 views
12

Если код Delphi был написан с синхронизацией для сериализации доступа к основному потоку VCL, но этот код затем используется в приложении, отличном от VCL, будет ли он синхронизироваться с основным потоком приложения или просто не имеет никакого эффекта вообще?Возможно ли использовать синхронизацию в приложении, отличном от VCL?


Пример:

procedure TMyThread.Execute; 
begin 

    // ... other code 

    Synchronize(SomeMethod); 

    // ... 

end; 

Давайте предположим, что

  • это приложение не-VCL, который имеет основную нить, которая выполняется в бесконечном цикле (или до момента прекращения)
  • основная нить не вызывает CheckSynchronize напрямую или в обработчике WakeMainThread
  • выполняется вторичный поток и выполняет синхронизацию (SomeMethod), как в примере выше

Будет ли винт зависать на линии Synchronize (SomeMethod)?

+0

Это приложение, отличное от VCL, под вашим контролем? Если нет, вы не можете использовать 'Синхронизировать'. –

+0

@DavidHeffernan Я могу представить 'synchronize (CallEventHandler)' в библиотеке, где я могу назначить метод обработчику событий. Компилятор не будет жаловаться, если это приложение, отличное от VCL. – mjn

+0

Конечно, компилятор не будет жаловаться. Это не имеет никакого отношения к синтаксису команды или области идентификаторов. Но @David ошибочно, что вы не можете использовать 'Synchronize'. Вы можете использовать все, что хотите. Вам просто нужно публиковать, что вы используете его, чтобы потребитель вашей библиотеки знал, что нужно использовать 'CheckSynchronize'. Я не знаю, что произойдет, если хост не выполнит свою часть контракта. Не стесняйтесь писать тестовую программу и сообщать о своих результатах здесь. –

ответ

9

TThread предоставляет средства для программ, не относящихся к VCL, для проверки очереди синхронизации, поэтому они могут продолжать использовать многопоточные библиотеки, которые ожидают синхронизации своих методов. Это описано в documentation for CheckSynchronize. Помните, что это задача приложения для проверки очереди, а не вашей библиотеки.

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

+0

см. Мое редактирование: DocWiki немного неясен, он читается так, как будто назначение WakeMainThread и вызов CheckSynchronize - это дополнительная оптимизация. – mjn

+0

Назначение 'WakeMainThread' - это оптимизация. Ожидается, что основной поток разбудит себя * в конце концов * и заметит новые синхронизированные задачи для выполнения, но 'WakeMainThread', если он предоставлен, сообщает основному потоку немедленно просыпаться *. Он сокращает время ожидания. –

+0

Извините, что удалил свой предыдущий комментарий! Я прочитал в вашем комментарии «Я не знаю, что произойдет, если хост не выполнит свою часть контракта. 'и затем удалил его, считая, что ответить не так просто – mjn

6

Опасно ли использовать синхронизацию в приложении, отличном от 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

+1 и о 'Synchronize', никогда не используйте его. Нить не должна зависеть от того, что находится за пределами ее области. Лучше использовать неблокирующие вызовы, такие как «PostMessage» или «TThread.Queue». См. Ответ [mghie's] (http://stackoverflow.com/users/30568/mghie) на [лучше ли использовать «синхронизацию» TThread или использовать «Сообщения окна для IPC между основным и дочерним потоком?] (Http: // stackoverflow .com/a/1806947/576719) для резюме. –

1

Поскольку вы помещаете код Delphi в библиотеке для других приложений для использования, я бы не советовал использовать Synchronize() вообще, так как вы нить не имеет ни малейшего понятия о том, что происходит вне себя. Лучшим выбором является то, чтобы поток показывал событие обратного вызова, которое поток может вызывать в своем собственном контексте, когда это необходимо, а затем позволяет приложению предоставлять обработчик функции обратного вызова, который решает наилучший способ синхронизации с основным потоком приложения по мере необходимости.

Смежные вопросы