主页
Top.Mail.Ru Yandeks.Metrika
论坛:“主要”;
当前存档: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]

> Naberezhnye S.(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]

> Naberezhnye S.(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]

> Naberezhnye S.(21.03.02 00:01)
>Ну и?
?

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

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



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

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

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

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]

По-моему что-то ты с тайм аутом перемудрил. Зачем он тебе здесь нужен? Чтобы навсегда не завистнуть второй параметр ф-ции используется. И зачем тебе именно в этом месте понадобился тоже не совсем ясно. Прочем надо видеть весь код, чтобы сказать окончательно... Если тебе надо ждать нескольких событий, можно использовать 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)
否则......
А ресурсы - event тоже ресурсы.



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

> Naberezhnye S.(21.03.02 03:38)
>А ресурсы - event тоже ресурсы.

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



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

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



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

> Naberezhnye S.(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]

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

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


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

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



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

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

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

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

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



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

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

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



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

>亚历山大
А как ты думал ?!
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), программа ресурсы не будет занимать.
> Naberezhnye S.(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 Quay S.
Логично. То есть если в списке процессов мой ехешник отстутствует, значит стопудово и потока тоже нет.
Это мне и надо было выяснить. Спасибо.



Страницы: 1 整个分支

论坛:“主要”;
当前存档:2002.04.01;
下载:[xml.tar.bz2];

楼上









内存:0.72 MB
时间:0.05 c
14-306
Viktor Scherbakov
2002-02-19 09:40
2002.04.01
多边形区域


1-220
Марина
2002-03-20 11:13
2002.04.01
未知(对我而言)数据类型


1-225
VJar
2002-03-20 16:10
2002.04.01
由星号隐藏的文本


1-138
听起来
2002-03-22 02:22
2002.04.01
是否可以将String转换为PChar?


1-213
VA-X
2002-03-20 11:54
2002.04.01
从Word导入





南非荷兰语 阿尔巴尼亚人 阿拉伯语 亚美尼亚 阿塞拜疆 巴斯克 白俄罗斯 保加利亚语 加泰罗尼亚 简体中文 中国(繁体) 克罗地亚 捷克 丹麦语 荷兰人 英语 爱沙尼亚语 菲律宾人 芬兰 法文
加利亚西语 格鲁吉亚语 德语 希腊语 海地克里奥尔语 希伯来语 印地语 匈牙利 北日耳曼语 印度尼西亚人 爱尔兰语 意大利语 日本性玩偶 韩语 拉脱维亚 立陶宛 马其顿 马来语 马耳他语 挪威语
波斯语 波兰语 葡萄牙语 罗马尼亚 俄语 塞尔维亚 斯洛伐克 斯洛文尼亚 西班牙语 斯瓦希里 瑞典语 泰国人 土耳其 乌克兰 乌尔都语 越南人 威尔士语 意第绪语 孟加拉 波斯尼亚
宿务 世界语 古吉拉特语 豪萨语 苗族 伊博 爪哇 卡纳达语 高棉 老挝 拉丁语 毛利 马拉 蒙古人 尼泊尔 旁遮普 索马里 泰米尔人 泰卢固语 约鲁巴语
祖鲁
英文 Французский Немецкий Итальянский Португальский 俄文 Испанский