Главная страница
    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]

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



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

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

Наверх




Память: 0.57 MB
Время: 0.04 c
1-1089703323
Vilux
2004-07-13 11:22
2004.07.25
Таскбар


14-1089057114
DeadMeat
2004-07-05 23:51
2004.07.25
Расписание


4-1086088360
Stany
2004-06-01 15:12
2004.07.25
библиотека для программирования на API


3-1088765847
Nikolai_S
2004-07-02 14:57
2004.07.25
Как записать в поле binary файл и потом считать его обратно?


4-1087321751
juiceman
2004-06-15 21:49
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
Английский Французский Немецкий Итальянский Португальский Русский Испанский