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

Вниз

Как можно запретить вызов even ta пока не отработал другой event   Найти похожие ветки 

 
SergP   (2003-08-15 21:12) [0]

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

Например в одном объекте произошло событие A. Как мне запретить вызов обработчика событий Б этого или другого объекта, пока не отработал A?

А то ИМНО из-за этого иногда вылазят ошибки типа Access violation .....


 
Романов Р.В.   (2003-08-15 21:43) [1]

Как то все запутано объясняешь...
Не может обработчик события Б вызываться во время выполнения обработчика события А (в однопоточном приложении).
Если нужно запретить обработчик введи флаг который будет устанавливаться в одной процедуре и блокировать другую.


 
Vuk   (2003-08-15 21:58) [2]

to Романов Р.В.:
>Не может обработчик события Б вызываться во время выполнения
>обработчика события А (в однопоточном приложении).
Очень даже может. Например, Вы пишете присвоение свойству какого-нибудь компонента, а он в ответ на это действие вызывает какой-нибудь OnChange. А насчет флага - все правильно.


 
Юрий Зотов   (2003-08-15 21:58) [3]

> SergP © (15.08.03 21:12)

Вообще-то, прав:
Романов Р.В. © (15.08.03 21:43) [1]

Заблокировать можно и без флагов:

procedure TForm1.EventA(...)
begin
SomeComponent.OnEventB := nil;
try
...
finally
SomeComponent.OnEventB := EventB
end
end;

procedure TForm1.EventB(...)
begin
...
end;

Но это не поможет. Потому что причина AV не в этом.


 
Юрий Зотов   (2003-08-15 22:02) [4]

Елы-палы... а ведь и правда может.
Но заблокировать все равно можно и без флагов.


 
Романов Р.В.   (2003-08-15 22:12) [5]


> Vuk © (15.08.03 21:58) [2]

Ну да. Перепутал событие с сообщением


 
SergP   (2003-08-15 22:12) [6]


> Романов Р.В. © (15.08.03 21:43) [1]
> Не может обработчик события Б вызываться во время выполнения
> обработчика события А (в однопоточном приложении).


Так я специально повставлял в каждый обработчик нечто типа:

begin
memo1.lines.add("начало обработки события N");
...
...
...
memo1.lines.add("конец обработки события N");
end

И вижу что там полный беспорядок происходит при работе проги:
типа:
начало ...1
начало ...2
конец....2
конец...1
и даже еще хуже бывает.


> SomeComponent.OnEventB := nil;


SomeComponent - это имеется ввиду все компоненты, или нужно конкретный указывать?


> Но это не поможет. Потому что причина AV не в этом.


Возможно. Но это упростит мне отладку...
А вообще какие причины подобных ошибок бывают?


 
Романов Р.В.   (2003-08-15 22:18) [7]

Причины простые. Обращение к еще не созданному или уже мертвому объекту


 
Anatoly Podgoretsky   (2003-08-15 22:23) [8]

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


 
SergP   (2003-08-15 22:25) [9]


> Заблокировать можно и без флагов:

Еще вопрос: В твоем примере. Если вызывается event A, при этом блокируются все другие event"ы. Но будут ли они вызываться после завершения A, если компонент "захотел" их сгенерировать в процессе работы A?


 
Vuk   (2003-08-15 22:51) [10]

to SergP:
Блокируйте лучше выполнение обработчиков при помощи флагов. Оно так проще. В конце концов может оказаться, что один флаг нужно будет проверять в нескольких обработчиках. Манипулирование одним флагом будет проще, чем переопределение несколько обработчиков.

to Романов Р.В.:
>Ну да. Перепутал событие с сообщением
Что самое интересное, обработчики оконных сообщений теоретически тоже могут сработать во время выполнения другого обработчика. Есть такой метод у TControl - Perform.


 
Романов Р.В.   (2003-08-15 22:57) [11]

Vuk
Уболтал, черт языкастый :)
(с) Властелин колец part II


 
Vuk   (2003-08-15 23:01) [12]

:o)


 
SergP   (2003-08-15 23:02) [13]


> to SergP:
> Блокируйте лучше выполнение обработчиков при помощи флагов.
> Оно так проще. В конце концов может оказаться, что один
> флаг нужно будет проверять в нескольких обработчиках. Манипулирование
> одним флагом будет проще, чем переопределение несколько
> обработчиков.


так , что-ли?

begin
while flag do Application.ProcessMessage;
flag:=true;

....

flag:=false;
end;


 
SergP   (2003-08-16 03:54) [14]


> так , что-ли?
>
> begin
> while flag do Application.ProcessMessage;
> flag:=true;
>
> ....
>
> flag:=false;
> end;


Но даже если так делать, то ничто не может гарантировать что другой event не сработает когда первый находится между
while flag do Application.ProcessMessage;
и
flag:=true;

Кстати. Если если event срабатывает в процессе работы другого event"a , они оба будут работать в разных потоках, или в одном?


 
Юрий Зотов   (2003-08-16 09:07) [15]

> SergP © (16.08.03 03:54) [14]

Если Вы хотите ЗАДЕРЖАТЬ обработку второго события до окончания обработки первого (а не ОТМЕНИТЬ ее), то ProcessMessages не спасет, придется ручками строить стек событий, в нем запоминать порядок их возникновения, а потом их отрабатывать

А если хотите ОТМЕНИТЬ, то все гораздо проще. В Private формы добавьте FInEvent: boolean, а во ВСЕХ обработчиках напишите:

begin
if not FInEvent then
begin
FInEvent := True;
try
... // Код самой обработки
finally
FInEvent := False
end
end
end;

> Если если event срабатывает в процессе работы другого
> event"a , они оба будут работать в разных потоках, или в одном?

У Вас приложение однопоточное? Откуда же возьмется второй поток?


 
SergP   (2003-08-16 10:41) [16]


> У Вас приложение однопоточное? Откуда же возьмется второй
> поток?


Однопоточное. Я дополнительных потоков не создаю.
Но ведь если объект вызывает обработчик, когда работает другой обработчик, то получается что сам объект создает свои потоки для своей работы. Вот и хотел узнать не создает ли он сам дополнительных потоков для своих event"ов....


 
Юрий Зотов   (2003-08-16 11:25) [17]

> SergP © (16.08.03 10:41) [16]

> получается что сам объект создает свои потоки для своей
> работы.

Откуда же это получается? Конечно, объект МОЖЕТ это сделать, но вовсе не обязательно. В подавляющем большинстве случаев (если не во всех случаях) объекты Delphi этого и не делают. Потому что иначе может возникнуть проблема. Дело в том, что разработчик объекта никак не может заранее знать, что именно напишет юзер этого объекта в своем обработчике (а написать можно что угодно). Поэтому, если запустить юзерский обработчик в отдельном потоке, то может возникнуть конфликт с однопоточной моделью VCL. Например, если юзер напишет какую-то визуальную обработку, которая должна выполняться в контексте главного потока, а будет выполнена в контексте дополнительного (см. TThread.Synhronize).

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

> Вот и хотел узнать не создает ли он сам дополнительных потоков
> для своих event"ов....

Вы поймите главное - понятие "событие объекта" в концепции VCL никак с потоками не связано, а с их синхронизацией - тем более. Просто-напросто при определенных условиях объект проверяет, назначен ли в его поле адрес юзерского метода и, если назначен - то вызывает этот метод, в том же самом потоке. Вот вызов этого метода и называется "произошло событие объекта". Вот пример классической (и самой распространенной) схемы события объекта, которое происходит при изменении его свойства:

type
TMyObject = class(...)
private
FMyProp: integer;
FOnMyPropChange: TNotifyEvent;
procedure SetMyProp(const Value: integer);
protected
procedure DoMyPropChange; dynamic;
published
property MyProp: integer
read FMyProp write SetMyProp default 0;
property OnMyPropChange: TNotifyEvent
read FOnMyPropChange write FOnMyPropChange;
end;

procedure TMyObject.SetMyProp(const Value: integer);
begin
if FMyProp <> Value then
begin
FMyProp := Value;
DoMyPropChange // Вызываем метод диспетчеризации
end
end;

procedure TMyObject.DoMyPropChange;
begin
// Проверяем и вызываем юзерский обработчик
if Assigned(FOnMyPropChange) then FOnMyPropChange(Self)
end;

Таким образом, если теперь написать
MyObject.MyProp := 1
то сработает метод SetMyProp и будет вызван обработчик события OnMyPropChange (если юзер его назначил). То есть - как бы произошло событие, а на самом деле просто последовательный вызов методов, один из другого.

Вот и все. Как видите - никаких дополнительных потоков и уж тем более никакой их синхронизации. Это и сеть событие ОБЪЕКТА, а вот Event, как объект синхронизации - это совершенно другая штука, к рассмотренному НИКАК не относящаяся.



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

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

Наверх





Память: 0.51 MB
Время: 0.011 c
14-1579
_Alex_
2003-08-11 15:57
2003.09.01
Компиляция CHM


14-1615
Anton
2003-08-13 10:24
2003.09.01
Ищу компоненты Delphi


7-1695
Chieftain
2003-06-18 18:26
2003.09.01
Есть *.vxd - файл. Как заставить систему видеть *.vxd файл?


7-1683
pauk
2003-06-16 15:43
2003.09.01
Принтеры


14-1639
POK
2003-08-12 15:28
2003.09.01
DBLookUpComboBox випадания по желанею!





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский