Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.006 c
6-279
Pimin
2002-01-18 03:08
2002.04.01
Заполняем форму Twebbrowseroм


1-92
D'Aron
2002-03-21 10:17
2002.04.01
Delphi3->Delphi6


3-66
Malder
2002-03-08 14:37
2002.04.01
ЛЮДИ, помогите. Такая ошибка... я ничего не понимаю


4-347
unikum
2002-01-31 19:41
2002.04.01
Подкаталоги


1-194
sammy
2002-03-19 09:33
2002.04.01
Про trial-version





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