![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TThread: Как создать свой объект-сигнализатор? [D5]
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.