Форум: "Основная";
Текущий архив: 2002.04.01;
Скачать: [xml.tar.bz2];
Вниз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;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.005 c