Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.04.01;
Скачать: CL | DM;

Вниз

TThread: Как создать свой объект-сигнализатор?   Найти похожие ветки 

 
lipskiy ©   (2002-03-20 21:46) [0]

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


 
lipskiy ©   (2002-03-20 21:56) [1]

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


 
vuk ©   (2002-03-20 21:56) [2]

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

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


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

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


 
lipskiy ©   (2002-03-20 22:03) [4]

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


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

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

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



 
vuk ©   (2002-03-20 22:05) [6]

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


 
Suntechnic ©   (2002-03-20 22:06) [7]

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


 
Suntechnic ©   (2002-03-20 22:09) [8]

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


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

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

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


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

> Suntechnic © (20.03.02 22:09)

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


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


> lipskiy ©

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


 
Suntechnic ©   (2002-03-20 23:54) [12]

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

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


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

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


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


> Suntechnic © (20.03.02 23:54)


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

Ну и?

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

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


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

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

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

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


 
lipskiy ©   (2002-03-21 01:14) [15]

Народ! Всем спасибо, разобрался, все заработало.
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 02:19) [16]

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


 
vuk ©   (2002-03-21 03:20) [17]

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

При ожидании в 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;



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


> Suntechnic © (21.03.02 00:23)

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


 
Suntechnic ©   (2002-03-21 03:42) [19]

>Набережных С. (21.03.02 03:38)
>А ресурсы - event тоже ресурсы.

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


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

Я достаточно хорошо и долго знаком с предметом. А вещи действительно очевидные.


 
Suntechnic ©   (2002-03-21 03:58) [21]

>Набережных С. (21.03.02 03:52)
Вот и чудненько.

Только один совет напоследок. Воплоти свою идею в жизнь. Запусти тестовый пример и посмотри в Task Manager-е сколько процессорного времени будет пожираться твоей программой. Того глядишь и взгляд свой на этот вопрос изменишь...


 
lipskiy ©   (2002-03-21 11:59) [22]

Собственная переменная TimeOut у меня содержит полный таймаут, например - 60 сек, если нет коннекта - стоп. И по декременту через каждую секнду внутри цикла while я печатаю на главную форму оставшееся время ожидания, за этим и нужен цикл.

От компонента DialUp можно получить события connect/noconnect, но просто я не знаю, можно ли возбудить сигнализатор с параметром? Я сейчас просто флажок глобальный ставлю - с каким результатом возник этот один сигнализатор - при коннекте или при неконнекте. Но мне это не очень нравится.

Вот, вариант, предложенный vuk © (21.03.02 03:20) с WaitForMultipleObjects я просто не знал, думаю подойдет.

Хотя если можно-таки возбудить один сигнализатор с параметром - то это будет удобнее (Ну что-то типа SetEvent(True) или SetEvent(False)). Так никак нельзя?



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


> Suntechnic © (21.03.02 03:42)

Не знаю, есть ли смысл продолжать, но все-же отвечу. Есть такая штука - вытесняющая многозадачность. Она в полной мере реализована в NT и почти в полной в 9X. Любой поток получит ровно столько процессорного времени, сколько ему предоставит ОС в соответствии с его приоритетом. Если в данный момент нет других активных потоков, он получит все процессорное время(за вычетом расходов ядра). Если есть - получит свою долю. В рассматриваемом случае никакого хоть сколько-нибудь заметного влияния ни на систему, ни на приложение он не окажет, и никаких ресурсов не "сожрет", тем более, что запускается на несколько минут.
Прикинь, сколько сейчас активных потоков в сервере, через который мы общаемся и как это влияет на время отклика для отдельного клиента.
P.S. Мало смотреть на Task Manager, надо-бы еще понимать смысл увиденного.


> lipskiy ©

Если ты работаешь под 9х, будь очень осторожен с WaitFor... без таймаута. Я довольно давно не имел с 9х дела, но помню, что там с ней гораздо легче попасть в непроходимый тупик, чем под NT.
Такой, из которого выход - только через "магическую тройку", а то и Reset.


 
Suntechnic ©   (2002-03-21 15:38) [24]

>Набережных С. (21.03.02 14:56)
Ты не можешь понять одной вещи. Поток НИЧЕГО не делает, кроме как ждёт событие, а процессорное время пожирает по полной программе(что тебе и продемонстрирует Task Manager). Нет оно то конечно можно и так, но ЗАЧЕМ? Если можно сделать чтобы поток просто спал до наступления события ни на что не претендовал.

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


Вот это по нашенски. Прямо как в анекдоте "...посмотрел я на карту, сколько там той Кубани..."

P.S. У меня натура такая пытаюсь людям глаза открыть, даже если они этого и не хотят. Надо наверное с этим заканчивать...


 
lipskiy ©   (2002-03-21 15:40) [25]

> Не знаю, есть ли смысл продолжать
Есть! Я всегда читаю свои ветки до конца и не свои, но заинтересовавшие - тоже, ти всегда рад новой инфе.

Работаю под Win2k, но прога должна нормально жить под любой ОС - распространяется свободно через инет. Под "работаешь" имеется ввиду только "пишешь" или вообще где она может быть запущена?

А таймаут я ставлю 1000 (второй параметр WaitForSingleObject, да?), так что застрять не должен.

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


 
Aleksandr ©   (2002-03-21 15:40) [26]

Сорри, коллеги, что-то я тут немного не уловил темы...
То есть, если у меня в программе есть потоки с таким вот телом:

repeat
if FoundWork then
DoSomething;
Sleep(2000)
until Terminated;</>
то они будут жрать ресурсы?


 
Digitman ©   (2002-03-21 15:46) [27]

>Aleksandr
А как ты думал ?!
DoSomething - процедура ? она ж требует процессорное время для выполнения инструкций, ее составляющих ?


 
Suntechnic ©   (2002-03-21 15:48) [28]

>Aleksandr © (21.03.02 15:40)
В таком варианте как у тебя он 2 секунды ничего делать не будет.

Надо условие задачи видеть, чтобы сказать имеет ли это смысл или нет. В случае lipskiy условие описано.

>lipskiy © (21.03.02 15:40)
>Как убедиться, что поток умер?
GetExitCodeThread пробовал?


 
Aleksandr ©   (2002-03-21 15:53) [29]

2 Digitman
Я имею в виду, будет жрать ресурсы в случае простоя, то есть когда DoSomething не выполняется?


 
vuk ©   (2002-03-21 15:54) [30]

to Aleksandr:
Все зависиот от кода, которого мы не видим (FoundWork и DoSomething). А вот завершения Вашего потока придется ждать как минимум 2 секунды.


 
Aleksandr ©   (2002-03-21 16:03) [31]

Слушайте, может, я вам тогда весь код модуля приведу, а вы взглядами спецов скажите, где там топоры висят?


 
lipskiy ©   (2002-03-21 16:15) [32]

> GetExitCodeThread пробовал?
:)) Ух ты. Нет, а что это такое и как это юзать?

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


 
Suntechnic ©   (2002-03-21 16:38) [33]

>lipskiy © (21.03.02 16:15)
>:)) Ух ты. Нет, а что это такое и как это юзать?
А хелп открыть пробовал? ;)

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

Поясни термин "вышел из программы", тогда может тебе и расскажут может что-то остаться висеть или нет....



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


> Suntechnic © (21.03.02 15:38)

Все я прекрасно понимаю. Но дело-то в том, что в ДАННОМ случае эти затраты не имеют НИКАКОГО практического значения. И в любом случае syspend c resume закрывают тему.
С другой стороны, создание и поддержка event - вполне конкретные затраты вполне конкретных ресурсов системы. Но и эти расходы в ДАННОМ случае не имеют значения. И в ДАННОМ случае ни одно из решений не имеет реальных преимуществ перед остальными.

Слушай, давай просто закончим тему. Утомило. Извини, если чем-то задел, я не хотел.

lipskiy © (21.03.02 15:40)

> Под "работаешь" имеется ввиду только "пишешь" или вообще
> где она может быть запущена?

Где запущена.

> А то слышал, что он может остаться там висеть.

Не останется. Под NT все потоки на выходе будут закрыты, под 9х есть риск зависнуть.
А вообще, чтобы узнать состояние любого объекта ОС, нужен его хендл.


 
lipskiy ©   (2002-03-21 17:23) [35]

> А хелп открыть пробовал? ;)
Пробовал, не получается :)
А если серьезно - не знаю английского, поэтому всегда проблема с хелпами. Знание английского на уровне чтения операторов Паскаля позволяет только в общих чертах получить представление о предмете.

> "вышел из программы"
Ну выгрузил ее, как еще можно из нее выйти? Close сделал или Terminate, или есть разница, как завершать?
Просто однажды наблюдал, как один веник тоже тыкался наугад с потоками, сделал для потока свою форму отображения результатов, и когда завершил основную программу, то поточная форма осталась висеть и работать - данные какие-то продолжали обновляться. Причем запущено было из-под IDE, и она нормально завершила прогон программы, без ошибок и вопросов, а поток работал...
Убивал только через диспетчер задач.


 
panov ©   (2002-03-21 17:26) [36]

>Aleksandr © (21.03.02 15:40)
Нет, пока выполняется Sleep(2000), программа ресурсы не будет занимать.
>Набережных С. (21.03.02 17:16)
С другой стороны, создание и поддержка event - вполне конкретные затраты вполне конкретных ресурсов системы.
Создание и поддержка event - действительно использует ресурсы.
Но использование этих ресурсов не так важно, ка использование процессорного времени. Я бы даже сказал - это абсолютно несопоставимые вещи.

>Aleksandr © (21.03.02 16:03)
Слушайте, может, я вам тогда весь код модуля приведу, а вы взглядами спецов скажите, где там топоры висят?

Не надо.

Если у тебя есть вопрос, то задавай его в отдельной ветке.


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


> lipskiy © (21.03.02 17:23)

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


 
lipskiy ©   (2002-03-21 18:21) [38]

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



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

Текущий архив: 2002.04.01;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.014 c
14-285
vic_vm
2002-02-18 14:29
2002.04.01
Вопрос к lel


3-43
YVaschuk
2002-03-06 13:36
2002.04.01
SQL Query в связанных таблицах


14-318
lel (A)
2002-02-15 14:41
2002.04.01
Почему, в любом обществе, всегда существует класс недовольных.??? 8(((((


1-150
СиндяшкинДВ
2002-03-21 07:13
2002.04.01
Поддержка DWG


1-135
Romik
2002-03-21 20:10
2002.04.01
Caption у формы