Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];

Вниз

Synchronize   Найти похожие ветки 

 
3APA3A   (2004-07-04 00:29) [0]

Что делает Synchronize? Я использую его и в общих чертах представляю что этот метод делает, но мне этого мало...


 
DrPass ©   (2004-07-04 00:34) [1]

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


 
3APA3A   (2004-07-04 00:46) [2]

Кое что прояснилось, но не до конца - ведь основной поток выполняется постоянно, хотя бы тот же цикл обработки сообщений.


 
jack128 ©   (2004-07-04 00:55) [3]


> ведь основной поток выполняется постоянно, хотя бы тот же
> цикл обработки сообщений.
ну так посмотри исходники и увидешь ;-)


 
3APA3A   (2004-07-04 01:21) [4]

Ok...


 
3APA3A   (2004-07-04 01:21) [5]

Уговорили... =)


 
Григорьев Антон ©   (2004-07-04 07:02) [6]

Synchronize через SendMessage передаёт управление основному потоку. При обработке этого сообщения основной поток выполняет указанную процедуру.


 
y-soft ©   (2004-07-04 07:56) [7]

Во многих случаях вместо пресловутого Synchronize гораздо выгоднее написать свою реализацию subj на основе PostMessage

Резон? SendMessage не возвращает управление до тех пор, пока посланное сообщение не будет обработано. В результате:

a. Тормозится вызывающий поток
b. Тормозятся все потоки, вызовы которых стоят в очереди этого потока
c. Тормозятся все потоки, вызовы которых стоят в очереди потока, который обрабатывает сообщение

Т.е. при слишком частом использовании Syncronize теряются все преимущества многопоточности


 
Mim1 ©   (2004-07-04 09:20) [8]


> [7] y-soft ©   (04.07.04 07:56)

Всякий овощ приносит пользу, будучи употребленным надлежащим образом в надлежащее время. (c) не помню


 
y-soft ©   (2004-07-04 10:00) [9]

>Mim1 ©   (04.07.04 09:20) [8]

Так и я о том же, только вот слишком часто люди не понимают, как это работает, и задают вопрос: почему безбожно тормозит? :)


 
Rouse_ ©   (2004-07-04 14:36) [10]

> [7] y-soft ©   (04.07.04 07:56)
А какая разница?
Во первых когда применяют Synchronize, ожидают что пока процедура не выполнится - код за ней не будет отрабатываться.
Это раз.
Ну а во вторых - не ужели ты думаешь что в то время пока отрабатывается первый PostMessage - в месте с ним отработается и второй?


 
y-soft ©   (2004-07-04 21:26) [11]

>Rouse_ ©   (04.07.04 14:36) [10]

Ну что ж, придется подробнее разъяснить, что я имел в виду

Сообщения, посланные PostMessage и SendMessage, помещаются в разные очереди, причем очередь синхронных сообщений имеет больший приоритет. Говоря о торможении, я имел в виду именно задержку обработки в очереди синхронных сообщений.  

Что касается PostMessage, то она (в отличие от SendMessage) возвращает управление сразу, как только сообщение будет поставлено в очередь вызываемого потока. И в этом случае вызывающий поток фактически не тормозится.

Теперь о том, так ли уж всегда необходимо  ждать завершения обработки посланного сообщения?

Как показывает опыт - чаще всего нет. В большинстве случаев Syncronize используется только для того, чтобы просто вызвать в основном потоке какие-то функции GUI (спасибо, Borland, за потоконебезопасность VCL!). От того, что перерисовка будет произведена не мгновенно, а через некоторый (небольшой) промежуток времени, ничего страшного не произойдет, зато не будет "скачков" и "замираний" курсора, отставания отображения ввода с клавиатуры и пропадания "тиков" таймеров.

Понятно, что я не имел в виду случаи, когда действительно необходимо ждать гарантированного завершения обработки события (хотя, честно говоря, для Win32 более естественным в этом случае является использование событий и Wait-функций или APC)

При большом желании можно, конечно, и с помощью слишком частого вызова PostMessage забить очередь асинхронных сообщений, но это уже из другой области :)

P.S. На всякий случай указываю авторитетные источники информации об особенностях работы очередей сообщений:

1. MSDN
2. Дж. Рихтер Глава 26

P.P.S. Ничего личного :)


 
Fay   (2004-07-05 03:44) [12]

2y-soft ©   (04.07.04 21:26) [11]

> 2. Дж. Рихтер Глава 26

Глава чего?


 
y-soft ©   (2004-07-05 07:51) [13]

>Fay   (05.07.04 03:44) [12]

Джеффри Рихтер "Windows. Создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows", "Питер", 2001, ISBN 5-272-00384-5


 
KSergey ©   (2004-07-05 08:45) [14]

> [11] y-soft ©   (04.07.04 21:26)

Ммм... Правда никто не возражает, может я правда что не понимаю, но всегда считал что ни о какой очереди сообщений для SendMеssage просто не существует.
Из ее тела вызывается оконная процедура (именно непосредственно выызывается) - и все. Вернулись из оконной процедуры - вернулись и из SendMessage. И в контексте того потока, который вызвал SendMessage.

Так о какой очереди сообщений идет речь в контексте SendMessage??


 
default ©   (2004-07-05 08:50) [15]

KSergey ©   (05.07.04 08:45) [14]
очередь есть, она, естественно, приоритетней чем очередь PostMessage
нафиг нужна?
процедура окна вызывается только в том потоке который создал окно соотв-ее данной  процедуре(чтобы не приходилось писать потокобезапасные процедуры окна)
а что будет если произв-ти вызов SendMessage в разных потоках при таких условиях?необходима очередь...


 
KSergey ©   (2004-07-05 08:52) [16]

> [15] default ©   (05.07.04 08:50)

Ну если так все уже классно придумано за нас... признаться не знал. Спасибо.


 
default ©   (2004-07-05 09:00) [17]

Григорьев Антон ©   (04.07.04 07:02) [6]
всё же через PostMessage
"procedure TThread.Synchronize(Method: TThreadMethod);
var
 SyncProc: TSyncProc;
begin
{$IFDEF MSWINDOWS}
 SyncProc.Signal := CreateEvent(nil, True, False, nil);
 try
{$ENDIF}
{$IFDEF LINUX}
   FillChar(SyncProc, SizeOf(SyncProc), 0);  // This also initializes the cond_var
{$ENDIF}
   EnterCriticalSection(ThreadLock);
   try
     FSynchronizeException := nil;
     FMethod := Method;
     SyncProc.Thread := Self;
     SyncList.Add(@SyncProc);
     ProcPosted := True;
     if Assigned(WakeMainThread) then
       WakeMainThread(Self);
{$IFDEF MSWINDOWS}
     LeaveCriticalSection(ThreadLock);
     try
       WaitForSingleObject(SyncProc.Signal, INFINITE);
     finally
       EnterCriticalSection(ThreadLock);
     end;
{$ENDIF}
{$IFDEF LINUX}
     pthread_cond_wait(SyncProc.Signal, ThreadLock);
{$ENDIF}
   finally
     LeaveCriticalSection(ThreadLock);
   end;
{$IFDEF MSWINDOWS}
 finally
   CloseHandle(SyncProc.Signal);
 end;
{$ENDIF}
 if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;"
procedure TApplication.WakeMainThread(Sender: TObject);
begin
 PostMessage(Handle, WM_NULL, 0, 0);
end;"


 
y-soft ©   (2004-07-05 09:05) [18]

>KSergey ©   (05.07.04 08:45) [14]

Придется цитировать:

...если поток посылает сообщение окну, созданному другим потоком, операции, выполняемые функцией SendMessage, значительно усложняются...
[Вырезано]
...чтобы один поток мог отправить сообщение окну, созданному другим потоком, система должна выполнить следующие действия.
   Во-первых, переданное сообщение присоединяется к очереди сообщений потока-приемника, в результате чего для этого потока устанавливается флаг QS_SENDMESSAGE. Во-вторых, если поток-приемник в данный момент выполняет какой-то код и не ожидает сообщений (через вызов GetMessage, PeekMessage или WaitMessage), переданное сообщение обработать не удастся - система не прервет работу потока для немедленной обработки сообщения. Но когда поток-приемник ждет сообщений, система сначала проверяет, установлен ли флаг пробуждения QS_SENDMESSAGE, и, если да, просматривает очередь синхронных сообщений, отыскивая первое из них. В очереди может находиться более одного сообщения. Скажем, несколько потоков одновременно послали сообщение одному и тому же окну. Тогда система просто ставит эти сообщения в очередь синхронных сообщений потока...


 
y-soft ©   (2004-07-05 09:09) [19]

>default ©   (05.07.04 09:00) [17]

всё же через PostMessage

А вот так реализовано в Delphi 5:

procedure TThread.Synchronize(Method: TThreadMethod);
begin
 FSynchronizeException := nil;
 FMethod := Method;
 SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
 if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;


 
default ©   (2004-07-05 09:28) [20]

y-soft ©   (05.07.04 09:09) [19]
понятно, я хотел написать что можно сделать и через SendMessage
просто вслучае с PostMessage-ом вызывающий поток засыпает по своему event-у в Synchronize после PostMessage в ожидании флага обработки, а в случае SendMessage подобные действия делает за нас ОС


 
Romkin ©   (2004-07-05 09:29) [21]

Не путайтесь. Начиная с D6 syncronize работает через критическую секцию, до этого - через SendMessage. И в том, и в другом случае вызывающий поток ждет окончания обработки


 
y-soft ©   (2004-07-05 09:33) [22]

>default ©   (05.07.04 09:28) [20]

Долго же Borland собирался, но все равно упорно останавливает поток-источник на время выполнения Synchronize :)


 
panov ©   (2004-07-05 10:05) [23]

>y-soft ©   (05.07.04 09:33) [22]

Так Synchronize для того и придумана была, чтобы выполнение процедуры происходило в основном потоке-)

Естественно, в это время дополнительный поток должен ожидать завершения выполнения целиком процедуры, которая указана в Synchronize. Т.е. процедура не может быть выполнена частично в потокобезопасном режиме.-)


 
y-soft ©   (2004-07-05 10:22) [24]

>panov ©   (05.07.04 10:05) [23]

Саша, не хочу заниматься самоцитированием ([7],[11])

Synchronize, конечно, полностью оправдывает свое название, но я о том, что в TThread очень не хватает метода Asynchronize :)


 
panov ©   (2004-07-05 10:26) [25]

y-soft ©   (05.07.04 10:22) [24]

Synchronize, конечно, полностью оправдывает свое название, но я о том, что в TThread очень не хватает метода Asynchronize :)

Ну это уже извращение бдет-)

От куда же заранее может быть известно, в каких условиях будет выполняться этот "Asynchronize" ;)

По отношению к какому потоку?


 
y-soft ©   (2004-07-05 10:36) [26]

>panov ©   (05.07.04 10:26) [25]

Простой жизненный пример:

Есть GUI поток и инструментальный поток, который ведет интенсивный обмен с сервером. При получении данных этот инструментальный поток обрабатывает их, помещает результаты в какую-то структуру и уведомляет поток GUI. Поток GUI визуализирует измененные результаты (это, кстати, из-за большого количества контролируемых объектов процесс довольно длительный). Делать это синхронно и заставлять ждать инструментальный поток неприемлемо, т.к. очень важны своевременное получение и обработка данных.

И это еще очень простой случай


 
default ©   (2004-07-05 11:10) [27]

y-soft ©   (05.07.04 10:36) [26]
можно передавать эти данные от сервера потоку диспетчеру который будет вслучае отсутствия(вначале) или занятости потока(ов) обработки создавать другой поток обработки
вслучае если число своб-ых потов больше 1 убивать лишние
потоки будут выставлять флаг занятости в Execute, например
вот и достигли параллельной обработки...


 
jack128 ©   (2004-07-05 11:34) [28]


> [27] default ©   (05.07.04 11:10)
А зачем такие сложности? Твой вариант будет напряжнее для системы, чем вариант y-soft"a. И вообще почему все так сильно против Asynchronize? вполне нормальная идея..


 
default ©   (2004-07-05 11:36) [29]

jack128 ©   (05.07.04 11:34) [28]
на мой взгляд, только так и надо делать учитывая
"т.к. очень важны своевременное получение и обработка данных."
объясни тогда как будет работать Asynchronize(


 
y-soft ©   (2004-07-05 11:37) [30]

>default ©   (05.07.04 11:10) [27]

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

Инструментальному потоку в приведенном примере совсем без разницы, когда и как поток GUI будет выполнять визуализацию, а важно лишь уведомить поток GUI, что данные обновились.

Аналогично и потоку GUI "по барабану", что конкретно делает инструментальный поток, ему важно лишь знать, что необходимо произвести перерисовку.

Необходимость в синхронизации возникает лишь при доступе к  совместно используемым данным (если таковые есть), но это дешевле сделать напрямую при помощи объектов синхронизации или функций InterlockedXXX

В общем случае потоки могут даже не знать о существовании друг друга (если для уведомления использовать события)...


 
Mim1 ©   (2004-07-05 11:45) [31]

[28] jack128 ©   (05.07.04 11:34)

Ага, поток уже умер, а тут подошла очередь и начал выполняться asyncronize. :)


 
y-soft ©   (2004-07-05 11:53) [32]

>Mim1 ©   (05.07.04 11:45) [31]

Ну и пусть умер. Какая разница, если Asynchronize всего-навсего ставит сообщение в очередь. Или устанавливает событие. Или безопасно изменяет общие данные. Когда придет очередь, поток-приемник вызовет свой обработчик, а не обработчик потока-источника


 
jack128 ©   (2004-07-05 12:00) [33]


> тогда как будет работать Asynchronize(
PostMessage в поток VCL. И не дожидаться обработки этого сообщения..

и вообще - зачем искуственно тормозить инструментальный поток синхронизацией?


 
y-soft ©   (2004-07-05 12:04) [34]

>jack128 ©   (05.07.04 12:00) [33]

PostMessage в поток VCL. И не дожидаться обработки этого сообщения..

В общем-то так чаще всего и делают. В параметрах сообщения можно передавать указатель на метод. Естественно, это не должен быть метод вызывающего потока, а то может получиться, как в [31] :)


 
default ©   (2004-07-05 12:26) [35]

jack128 ©   (05.07.04 12:00) [33]
"Инструментальному потоку в приведенном примере совсем без разницы, когда и как поток GUI будет выполнять визуализацию"в таком случае это как говорится и козе понятно


 
Григорьев Антон ©   (2004-07-05 13:37) [36]


> y-soft ©   (05.07.04 11:53) [32]
> >Mim1 ©   (05.07.04 11:45) [31]
>
> Ну и пусть умер. Какая разница, если Asynchronize всего-навсего
> ставит сообщение в очередь. Или устанавливает событие. Или
> безопасно изменяет общие данные. Когда придет очередь, поток-приемник
> вызовет свой обработчик, а не обработчик потока-источника


А внутри метода, который используется в Asynchronize, есть доступ к полям TThread"а. А поток-то уже умер, объект нити уничтожен. Всё, AV.


 
y-soft ©   (2004-07-05 13:51) [37]

>Григорьев Антон ©   (05.07.04 13:37) [36]

См. [34]. И вообще: кто и где сказал, что это непременно должен быть метод вызывающего потока?

Вот все, что сказано в Help:


TThread.Synchronize

type TThreadMethod = procedure of object;
procedure Synchronize(Method: TThreadMethod);

Description

Synchronize causes the call specified by Method to be executed using the main VCL thread, thereby avoiding multi-thread conflicts. If you are unsure whether a method call is thread-safe, call it from within the main VCL thread by passing it to the Synchronize method.

Execution of the thread is suspended while Method is executing in the main VCL thread.

Note: You can also protect unsafe methods using critical sections or the multi-read exclusive-write synchronizer.


 
y-soft ©   (2004-07-05 14:03) [38]

>Григорьев Антон ©   (05.07.04 13:37) [36]

(продолжение)

Пример для Synchronize привожу только потому, что в гипотетическом ASynchronize в качестве параметра передается точно такой же TThreadMethod (который procedure of object).

Это может быть метод любого объекта, кроме вызывающего TThread


 
Тимохов ©   (2004-07-05 14:56) [39]


> Григорьев Антон ©   (04.07.04 07:02) [6]

прошу прощения - может где то выше уже было: нет вермени читать.

synchronioze юзает postmessage (в д6).

по сути работает все же как send - реализовано через post + waitforsingleobject (некий ивент)


 
Тимохов ©   (2004-07-05 14:58) [40]


> Тимохов ©   (05.07.04 14:56) [39]

да... я конечно очень оригнален со своим замечанием :)))))


 
Григорьев Антон ©   (2004-07-05 15:06) [41]


> Тимохов ©   (05.07.04 14:58) [40]
>
> > Тимохов ©   (05.07.04 14:56) [39]
>
> да... я конечно очень оригнален со своим замечанием :)))))


А я не буду оригинален с ответом: см. [19]. Я ведь до сих пор на пятёрке сижу.


 
Serginio666   (2004-07-05 15:29) [42]

В D7 реагирует на SetEvent

procedure SignalSyncEvent;
{$IF Defined(LINUX)}
const
 Dummy: Byte = 0;
var
 nRead: Integer;
{$IFEND}
begin
{$IF Defined(MSWINDOWS)}
 SetEvent(SyncEvent);
{$ELSEIF Defined(LINUX)}
 if (ioctl(SyncEvent.ReadDes, FIONREAD, @nRead) = 0) and (nRead = 0) then
   __write(SyncEvent.WriteDes, Dummy, SizeOf(Dummy));
{$IFEND}
end;

В procedure TApplication.WndProc(var Message: TMessage);
реагирует на сообщение
WM_NULL:
         CheckSynchronize;

и соответственно в CheckSynchronize снимает событие и выполняет нужный метод


 
Тимохов ©   (2004-07-05 16:17) [43]


> Григорьев Антон ©   (05.07.04 15:06) [41]

да понял я - уже прочел.

виноват - поспешил с соображением :))))


 
Mim1 ©   (2004-07-05 16:44) [44]


> [38] y-soft ©   (05.07.04 14:03)


Вот по этому его и не сделали. Можно сделать но с кучей оговорок и т.д. Лучше пользуйтесь PostMessage.


 
y-soft ©   (2004-07-05 20:12) [45]

>Mim1 ©   (05.07.04 16:44) [44]

Лучше пользуйтесь PostMessage.

А я обычно и пользуюсь :)

Хотя думал что-то над этой веткой и в принципе решил, что написать класс с Asynchronyze вполне смог бы... Время будет - может напишу и выложу :)


 
Mim1 ©   (2004-07-06 08:10) [46]


> [45] y-soft ©   (05.07.04 20:12)

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

> Время будет - может напишу и выложу :)

Лучше не тратьте его зря.


 
y-soft ©   (2004-07-06 15:23) [47]

>Mim1 ©   (06.07.04 08:10) [46]

Я конечно извиняюсь, а кто будет вызывать этот метод?

Вызывать его будет функция инструментального потока для того, чтобы просто уведомить поток GUI, что он должен выполнить какой-то метод в удобное для потока GUI время. Т.е. сделать то же, что делает Synchronize, но не дожидаясь, когда метод начнет выполняться

Фактически этот ASyncronize будет просто вызывать PostMessage, передавая в одном из параметров указатель на какой-то внешний метод и сразу же возвращать управление. В этом и весь смысл - не заставлять инструментальный поток ждать, когда это не нужно.

Насчет ограничений. В VCL и вообще в Windows существует их множество, но они как-то не мешают жить программисту. Теоретически ведь можно много чего сделать такого, что не приведет ни к чему хорошему и без всяких Asinchronize :)
Вы ведь наверняка не вызываете в конструкторе объекта его деструктор? И не делаете перерисовку TControl, если не назначен Parent? :)

К тому же я собираюсь написать не какой-то новый потомок TThread, а класс-оболочку для удобной работы сразу со множеством потоков (скорее всего наследую его от TWinControl, чтобы не надо было подменять оконную функцию главного окна). Причем прямого доступа у программиста к ним не будет, только через методы и свойства контейнера-родителя. Вместо виртуального Execute у каждого элемента (это будут потомки TCollectionItem) будет событие OnExecute, в котором Вы и будете вызывать по мере необходимости Synchronize и ASynchronize. Написанный в этом событии код и будет выполняться в функции потока. Заодно и поправлю недостаток TThread при работе с исключениями в функции потока...

Т.е. есть желание написать удобный компонент-оболочку для комфортной "визуальной" работы с потоками при написании VCL приложений. Кидаете его на форму, прямо в IDE содаете сколько надо потоков, назначаете им обработчики и все! И не более того :) IMHO для Delphi такой подход более естественен, чем написание каждый раз классов-потомков...


 
Ihor Osov'yak ©   (2004-07-14 04:05) [48]

моих две копейки. Мне кажется, синхронайз далеко не самое лучшее изобретение Борланда. Не раз приходилось наблюдать, как человек вмесо того, чтобы немного разобраться с sendmessage, postmessage, немного с обьектами синхронизации, начинал делать шаманские танцы вокруг синхронайз.. Причем, совсем не имея понятия, как это дело работает.. Причем на танцы идет много больще времени, чем собственно нужно для просветления в вопросах вокруг  send и postmessage.
Да, еще. И в большинстве случаев после просветления исчезает желание использовать синхронайз..


 
Ihor Osov'yak ©   (2004-07-14 04:09) [49]

сори, или что то с клиентом случилось, или со мной,  вытащил на верх ветку двухнедельной давности :-(.


 
Тимохов ©   (2004-07-14 11:18) [50]


> Ihor Osov"yak ©   (14.07.04 04:05) [48]


> Да, еще. И в большинстве случаев после просветления исчезает
> желание использовать синхронайз..

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



Страницы: 1 2 вся ветка

Форум: "Основная";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.61 MB
Время: 0.039 c
1-1089614892
ИМХО
2004-07-12 10:48
2004.07.25
Structured storage


4-1086903079
Zahar
2004-06-11 01:31
2004.07.25
Переменные окружения


3-1088500806
Jiny
2004-06-29 13:20
2004.07.25
Как автоматизировать триггер на SELECT из другой таблицы


1-1089290327
Helper
2004-07-08 16:38
2004.07.25
Поиск и замена строки в текстовом файле


6-1085414343
Игорь Н.
2004-05-24 19:59
2004.07.25
Как узнать есть ли сейчас соединение с интернетом?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский