Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TThread: Как создать свой объект-сигнализатор? [D5]


Страницы:   1 2

lipskiy ©   (2002-03-20 21:46:00) 

Народ! Никак не могу сообразить, как это делается.
Есть у меня поток, который обновляет данные через инет.
Создаю его, произвожу некоторую инициализацию, затем запускаю DialUp. И мне нужно подождать установки соединения. Компонент DialUp имеет событие OnConnect - при появлении этого события мне нужно продолжить выполнение потока.
Понятно, что нужно использовать WaitForSingleObject, но ему нужен Handle, а где мне его взять? То есть как получить Handle события OnConnect, что-ли... Запутался совсем.
Если можно ответить - то поподробнее, плз, первый раз с потоком вожусь.


Набережных С.   (2002-03-21 03:38:00) [21]


> Suntechnic © (21.03.02 00:23)

Можно.
while not Flag do
if not Terminated then Sleep(0)
else ...
А ресурсы - event тоже ресурсы.


vuk   (2002-03-21 03:20:00) [22]

Насчет двух объектов синхронизации. Я думаю, что это совершенно не обязательно в данном случае. Ведь состояние коннект/неконнект всегда можно узнать у компонента, отвечающего за соединение.

При ожидании в WaitForXXXObject можно задать таймаут для
ожидания(второй параметр функции, как заметил Suntechnic), так что никакие дополнительные счетчики просто не нужны.

if not terminated do
case WaitForSingleObject( Handle, Timeout ) of
WAIT_OBJECT_0 : <дождались>;
WAIT_TIMEOUT : <обработка таймаута>;
else
<обработка ошибки>
end;


Хотя... если честно, иногда лучше "просыпаться" и проверять состояние флага terminated, иначе поток, в случае попытки его прекращения будет "висеть" до истечения таймаута.

Но тогда возникают некоторые сложности с отсчетом времени до этого самого таймаута. Решить это можно тремя путями:

1. Таймер, который считает время до таймаута. При этом необходимо периодически "просыпаться и глядеть на часы" а также на флаг terminated.

2. Если дело происходит в NT/W2K/XP, дополнительный объект синхронизации - WaitebleTimer.

3. Завершать поток не по выставленному флагу terminated, а по еще одному Event"у.

Последний выриант мне нравится больше всего. При этом получается примерно следующий код:

var
Handles : array[0..1] of THandle;

...
Handles[0] := evtTerminate;
Handles[1] := evtWake;

if not terminated then
case WaitForMultipleObjects( 2, @Handles, false, Timeout ) of
WAIT_OBJECT_0 : <окончание работы потока>;
WAIT_OBJECT_0 + 1 : <дождались>;
WAIT_TIMEOUT : <обработка таймаута>;
else
<обработка ошибки>
end;


Suntechnic   (2002-03-21 02:19:00) [23]

По-моему что-то ты с тайм аутом перемудрил. Зачем он тебе здесь нужен? Чтобы навсегда не завистнуть второй параметр ф-ции используется. И зачем тебе whileименно в этом месте понадобился тоже не совсем ясно. Прочем надо видеть весь код, чтобы сказать окончательно... Если тебе надо ждать нескольких событий, можно использовать WaitForMultipleObjects, хотя опять же я не совсем уверен, что она здесь нужна. Надо всю логику видеть.


lipskiy   (2002-03-21 01:14:00) [24]

Народ! Всем спасибо, разобрался, все заработало.
DialUp.Open у меня вызывается из потока, так как сам экземпляр этого класса создается вместе с потоком.
Согласен, что цикл на флажок ставить не очень хорошо, тем более что DialUp-компонент работает внутри потока, ему нужны ресурсы.
Сделал с WaitForSingleObject и CreateEvent, SetEvent, как посоветовал vuk, за что ему большое спасибо, все работает как надо. Очень удобно, действительно.

У меня другой вопрос возник.
Вот я делаю цикл такой в потоке:

while
(WaitForSingleObject(EventConnectSuccessfull, 1000) <> WAIT_OBJECT_0)
and (TimeOut <> 0) do ...


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

Так вот, мне бы надо иметь не один сигнализатор, а два разных. И оба проверять в этом цикле. Один - EventConnectSuccessfull - типа соединение установлено успешно, а другой - EventConnectFailed - не удалось.
Как в этом случае правильно написать условие цикла?
Если я сделаю так:

while
((WaitForSingleObject(EventConnectSuccessfull, 1000) <> WAIT_OBJECT_0)
or (WaitForSingleObject(EventConnectFailed, 1000) <> WAIT_OBJECT_0))
and (TimeOut <> 0) do ...

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




Suntechnic   (2002-03-21 00:23:00) [25]

>Набережных С. (21.03.02 00:01)
>Ну и?
?

>Можно поставить Sleep, если это важно.

Нельзя. Потому как Sleep понятия не имеет, когда соединение будет установлено. На сколько ты поток присыпить собираешься? На 10 мск? На 1 мин? Может на час?.... на время вызова Sleep поток будет просто спать, вместо того, чтобы работать. Нечего изобретать велосипед там, где его уже давно изобрели...


Набережных С.   (2002-03-21 00:01:00) [26]


> Suntechnic © (20.03.02 23:54)


> DialUp.Open не вызывается из этого потока

Ну и?

> будет обычное пожирательство

Можно поставить Sleep, если это важно.


Suntechnic   (2002-03-20 23:54:00) [27]

>Набережных С. (20.03.02 22:19)

Flag:=false;
DialUp.Open;
while not Flag do;


>Никакого особого "пожирательства" не будет, если не задирать приоритет.

Во-первых, насколько я понял, соединение устанавливается асинхронно потоку, который обновляет данные. Это значит, что DialUp.Open не вызывается из этого потока. Во-вторых особого"пожирательства" не будет, будет обычное пожирательство.


Набережных С.   (2002-03-20 23:19:00) [28]


> lipskiy ©

Покажи код потока на всякий случай, а то сейчас насоветую...


Набережных С.   (2002-03-20 22:19:00) [29]

> Suntechnic © (20.03.02 22:09)

Никакого особого "пожирательства" не будет, если не задирать приоритет. Впрочем, после DialUp.Open можно просто делать Syspend, а в OnConnect снова пробуждать.


Набережных С.   (2002-03-20 22:14:00) [30]

Наверно, все-же надо уточнить:

while not Flag do if Terminated then ..-освобождение ресурсов и выход из потока.


Suntechnic   (2002-03-20 22:09:00) [31]

>Набережных С. (20.03.02 22:03)
Да нет. Флажок здесь как раз и неуместен. Во время ожидания подобный поток будет "жрать" ресурсы. А нам необходимо его перевести в состояние ожидание не потребляя ресурсы системы. Для этого и используются объекты синхронизации и Wait-ф-ции...


Suntechnic   (2002-03-20 22:06:00) [32]

На английском могу цельную книгу закинуть. На русском в Инете целиком навряд ли найдёшь... разве что отдельные главы...


vuk   (2002-03-20 22:05:00) [33]

Честно говоря, у меня сылки нет. :o( Только книга.


Набережных С.   (2002-03-20 22:03:00) [34]

Здесь не нужен WaitFor... Просто объяви глобальный флаг, который устанавливай в OnConnect, а в потоке напиши что-то типа

Flag:=false;
DialUp.Open;
while not Flag do;


lipskiy   (2002-03-20 22:03:00) [35]

2 vuk
А ссылочку мона на "почитать"?


vuk   (2002-03-20 22:00:00) [36]

Почитать можно у Рихтера. Довольно неплохо все расписано.


lipskiy   (2002-03-20 21:56:00) [37]

Где бы вообще по потокам что-нибудь для чайников и по-русски почитать?


vuk   (2002-03-20 21:56:00) [38]

Создается объект синхронизации Event (см. CreateEvent) и его handle передается и потоку и тому, кто будет его "будить". В нужный момент просто вызывается SetEvent.

Иногда для удобства можно использовать класс-оболочку TEvent.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо