Форум: "Основная";
Текущий архив: 2004.01.29;
Скачать: [xml.tar.bz2];
ВнизTThread + TTimer Найти похожие ветки
← →
snake1977 (2004-01-15 11:14) [0]Здравствуйте! Такая вот задача: есть несколько модулей в каждом из которых, с определенным интервалом времени должны выполняться определенные процедуры. Для того чтобы выполнение этих ппроцедур не мешало выполнению других процессов, я решил использовать TThread в котором запускаю таймер. Честно, я первый райз использую TThread и взял примерчик с этогоже сайта из статьи, но так и не понял как же мне запускать таймер в организованном потоке%((. Подскажите примером, как организовать такую вот работу.
вот то что у меня написано:
type TMyThread = class(TThread)
protected
procedure DoWork;
procedure Execute; override;
end;
implementation
procedure TMyThread.Execute;
begin
while not Terminated do
Synchronize(DoWork);
end;
procedure TMyThread.DoWork;
begin
....
end;
← →
Семен Сорокин (2004-01-15 11:18) [1]в Thread организовать таймер можно с помощью Sleep или GetTickCount внутри цикла.
← →
Тимохов (2004-01-15 11:19) [2]procedure TMyThread.Execute;
begin
while not Terminated do
begin
Synchronize(DoWork);
sleep(10000)
end
end
← →
Dred2k (2004-01-15 11:24) [3]Таймер в нитке??? Оригинально...
Просто засекай время по GetTickCount, отсчитывай и действуй в нужные моменты. А TTimer работает по событию, приходящему в форму (фактически - в рамках главной нити приложения). Кроме того, Synchronize сводит на нет весь эффект от использования отдельной нитки. Разделяй доступ к ресурсам через TCriticalSection или TEvent. Если нужно что-то "рисовать" (обращаться к VCL-объектам) - посылай сообщения через PostMessage, это надежно и довольно удобно.
← →
snake1977 (2004-01-15 11:26) [4]а в каком модуле описана процедура sleep ??
компилятор ругается что "неизвестный идентификатор sleep"
← →
Digitman (2004-01-15 11:28) [5]
> А TTimer работает по событию, приходящему в форму (фактически
> - в рамках главной нити приложения)
с какой это стати ?
тот код.поток, который создал экз-р TTimer, и будет извещаться о событиях созданного таймера... будет это осн.поток или доп.поток - значения не имеет
← →
snake1977 (2004-01-15 11:29) [6]>> Dred2k
>>Кроме того, Synchronize сводит на нет весь эффект от >>использования отдельной нитки
а по подробнее?? почему на нет сводит эффект?? и как тогда сделать чтобы каждая такая нить выполнялась паралельно?
← →
Dred2k (2004-01-15 11:29) [7]Windows
← →
Романов Р.В. (2004-01-15 11:32) [8]Запускай поток по таймеру расположенному на главной форме.
И зачем нужен поток когда все его операции выполяются в основном потоке
while not Terminated do
Synchronize(DoWork);
end;
← →
snake1977 (2004-01-15 11:32) [9]>>Digitman ©
так как засунуть то в поток таймер??
т.е. в процедуре execute фактически крутиться бесконечный цикл (ну до terminate есесно), а таймер срабатывает по событию.....
чего мне написатьто тогда в Execute??
← →
Digitman (2004-01-15 11:32) [10]
> snake1977
просто не используй Synchronize(), либо разберись в обоснованности использования этого метода в каждом конкретном случае
← →
Dred2k (2004-01-15 11:32) [11]> Digitman © (15.01.04 11:28) [5]
Ага, WM_TIMER по потокам гулять будет...
← →
Тимохов (2004-01-15 11:35) [12]Все таки не понял, чем sleep то не подходит? Или GetTickCount? Зачача то ведь решится.
← →
snake1977 (2004-01-15 11:35) [13]>>Романов Р.В. ©
>>Запускай поток по таймеру расположенному на главной форме.
должно крутиться несколько потоков одновременно.
>>
>>И зачем нужен поток когда все его операции выполяются в >>основном потоке
>>while not Terminated do
>> Synchronize(DoWork);
>>end;
и как тогда должны выглядеть эта процедура?? чтобы это было в отдельном потоке парарлельно с другими , причем каждый из них не должен мешать друг другу, т.е. не забирать на себя все процессорное время ??
← →
snake1977 (2004-01-15 11:37) [14]>>>Тимохов ©
Во время Sleep, что присходит с основным и другими потоками??
они продолжают свое выполнение или останавливаются?
← →
Dred2k (2004-01-15 11:38) [15]> snake1977 (15.01.04 11:29) [6]
Synchronize(DoWork); выполнит DoWork в рамках основной нитки приложения. То есть все нитки, фактически, будут постоянно друг друга ждать. Сия вещь нужна для корректной отработки вызовов к визуальным компонентам VCL. А так - зачем оно тебе? Нить считает, да считает... Если есть общие области данных (переменные и т.п.) - разделяй через критические секции или евенты. Как я уже говорил, можно и отображать без ожидания - сделай в окне общий обработчик своего собятия и посылай последнее из ниток без ожидания, в событие впихивай указатели на данные для отображения, освобождай по факту отображения - схема нормальная... Почитай про нитки - иначе сложно все это на коленке объяснять.
← →
Тимохов (2004-01-15 11:38) [16]snake1977 (15.01.04 11:37) [14]
Слип влияет на поток, в котором вызван.
← →
Семен Сорокин (2004-01-15 11:39) [17]Во время Sleep, что присходит с основным и другими потоками??
конечно продолжают работать, засыпает только поток, в котором ты делаешь Sleep
← →
Digitman (2004-01-15 11:39) [18]
> Dred2k © (15.01.04 11:32) [11]
> Ага, WM_TIMER по потокам гулять будет...
что значит "гулять" ?
тот поток, который вызвал SetTimer(), и будет получть адресованные ему (или окнам им созданным) индивидуальные WM_TIMER
← →
panov (2004-01-15 11:42) [19]>Dred2k © (15.01.04 11:32) [11]
Ага, WM_TIMER по потокам гулять будет..
С чего бы это?
В классе TTimer создается невидимое окно, которому и отсылается сообщение. И неважно, где создается таймер, в основном потоке, или в дополнительном.
← →
Dred2k (2004-01-15 11:45) [20]> panov © (15.01.04 11:42) [19]
Я о том же и говорил.
> Digitman © (15.01.04 11:39) [18]
Поток ничего получать не будет.
← →
Digitman (2004-01-15 11:56) [21]
> Dred2k © (15.01.04 11:45) [20]
> Поток ничего получать не будет
конечно не будет ... если руки кривые и нет понимания того, что каждый поток для обеспечения возможности принимать сообщения, должен организовать в том или ином виде логику приема/диспетчеризации/обработки этих сообщений
об основном потоке приложения позаботился сам Борланд, написав для "батонокидателей" метод Application.Run и вызывая его при инициализации GUI-приложения
об дополнительных же Борланд заботиться вовсе не обязан - организация подобной логики в доп.потоках , если угодно, уже некоторым образом выходит за рамки компетенции простого "батонокидателя"
← →
snake1977 (2004-01-15 11:58) [22]>>>Digitman ©
>>.... в том или ином виде логику приема/диспетчеризации/обработки этих сообщений...
подскажи где мона почитать об этом??
← →
Тимохов (2004-01-15 12:01) [23]Глянь как сделано в TApplication.Run.
← →
YuRock (2004-01-15 12:04) [24]> Digitman © (15.01.04 11:56) [21]
> об основном потоке приложения позаботился сам Борланд
> об дополнительных же Борланд заботиться вовсе не обязан
Да... Спасибо, конечно, Борланду. Если бы он еще так "позаботился" о главном потоке, чтобы из других потоков можно было бы хотябы слать сообщения через SendMessage окнам, созданным в главном потоке...
А так (при возникновении необхоимости, например, прорефрешить окно из другого потока) приходится либо постить сообщение, либо вообще отказываться от Application.Run ...
← →
Digitman (2004-01-15 12:06) [25]
> snake1977 (15.01.04 11:58) [22]
для начала скажи, почему
"я решил использовать TThread в котором запускаю таймер"
а не
"я решил использовать таймер в котором запускаю TThread"
?
мне пока неясна твоя логика, а от этого и решение/рекомендация зависит
← →
Dred2k (2004-01-15 12:10) [26]> конечно не будет ... если руки кривые и нет понимания того,
> что каждый поток для обеспечения возможности принимать сообщения,
> должен организовать в том или ином виде логику приема/диспетчеризации/обработки
> этих сообщений
Это мудро. Оценил.
> организация подобной логики в доп.потоках
Сообщение получит окошко, и плевать на то, какой поток его создал - забота системы. Винды, понимаешь... Без окошек - никуда.
← →
Verg (2004-01-15 12:17) [27]
> Сообщение получит окошко, и плевать на то, какой поток его
> создал - забота системы. Винды, понимаешь... Без окошек
> - никуда.
Окошко-то получит, а кто его (сообщение) заберет(обработает), а? Какой поток?
← →
Digitman (2004-01-15 12:22) [28]
> Dred2k © (15.01.04 12:10) [26]
> Сообщение получит окошко, и плевать на то, какой поток его
> создал - забота системы. Винды, понимаешь... Без окошек
> - никуда.
это не верно.
не оценил.
сообщение в любом случае получает не окошко, а кодовый поток, который сам должен заботиться об определении "адресата" : либо адресат - его окно, либо он сам.
и без окошек как раз "куда" ! ибо сообщение м.б. послано как окну, так и кодовому потоку... оба варианта вполне документированы и полностью работоспособны ... см. PostThreadMessage() - увидишь, что никакие окошки в параметрах этой ф-ции не фигурируют
← →
AKul (2004-01-15 12:23) [29]
> Dred2k © (15.01.04 11:24) [3]
> TTimer работает по событию, приходящему
> в форму (фактически - в рамках главной нити приложения).
>
Это Borland заставило его так работать (передавать событием).
Но Timer (Windows API) сам может вызывать процедуру, передаваемую ему при создании (используется callback).
← →
Dred2k (2004-01-15 12:23) [30]> Окошко-то получит, а кто его (сообщение) заберет(обработает), а? Какой поток?
В контексте потока-создателя и обработается. Есть варианты, а?...
← →
Digitman (2004-01-15 12:25) [31]
> Dred2k
Win32 предусматривает отдельные очереди для сообщений, адресованных код.потокам и сообщений, адресованных окнам (неважно какими код.потоками созданным)
← →
YuRock (2004-01-15 12:28) [32]> Verg © (15.01.04 12:17) [27]
> ошко-то получит, а кто его (сообщение) заберет(обработает), а? Какой поток?
Обработает его оконная процедура. В потоке, в котором создано окно.
← →
Digitman (2004-01-15 12:28) [33]
> Dred2k © (15.01.04 12:23) [30]
>
> В контексте потока-создателя и обработается. Есть варианты,
> а?...
есть.
см. AttachThreadInput(), позволяющая код.потоку 2 делать выборку из очереди сообщений потока 1
← →
Dred2k (2004-01-15 12:29) [34]> Digitman © (15.01.04 12:22) [28]
> сообщение в любом случае получает не окошко, а кодовый поток
Не факт. Может и не получить.
The function fails if the specified thread does not have a message queue. The system creates a thread"s message queue when the thread makes its first call to one of the Win32 USER or GDI functions.
← →
Digitman (2004-01-15 12:30) [35]
> > Dred2k
"выборка сообщений" и "обработка сообщений" - две разные вещи, не путай
← →
Nikolay M. (2004-01-15 12:31) [36]
> чтобы выполнение этих ппроцедур не мешало выполнению других
> процессов, я решил использовать TThread в котором запускаю
> таймер
RX-овый RxTimer, что-ли, пишется? Дык он вроде уже написан...
← →
AKul (2004-01-15 12:32) [37]Еще раз повторюсь:
Это Borland заставило его так работать (передавать событием).
Но можно использовать API-функцию SetTimer, которую настроить на вызов заданной процедуры (HWND=0).
← →
Verg (2004-01-15 12:34) [38]
> Но можно использовать API-функцию SetTimer, которую настроить
> на вызов заданной процедуры (HWND=0).
Из Help-а по SetTimer
When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
← →
Dred2k (2004-01-15 12:38) [39]> Digitman © (15.01.04 12:30) [35]
> "выборка сообщений" и "обработка сообщений" - две разные
> вещи, не путай
Ты насчет > Dred2k © (15.01.04 12:29) [34]
?
Обработка без выборки? Интересно...
Тем паче, что нет очереди - нет и содержимого. Тоже ведь вариант.
← →
Digitman (2004-01-15 12:40) [40]
> Dred2k © (15.01.04 12:29) [34]
> > Digitman © (15.01.04 12:22) [28]
>
> Не факт. Может и не получить.
"в любом случае" - здесь имелось ввиду не гарантия доставки сообщения, а то что именно кодовый поток ответственен за выборку сообщений изо всех его интересующих (и ассоциированных с ним и его окнами) очередей
> The function fails if the specified thread does not have
> a message queue. The system creates a thread"s message queue
> when the thread makes its first call to one of the Win32
> USER or GDI functions.
а это уже проблема того программера, который не удосужился предусмотреть такую ситуацию и тычет сообщение в еще не созданную очередь. не проверяя никак факт успешной или неуспешной постановки сообщения в очередь
поэтому одним из грамотных подходов к реализации корректной логики является следующий :
поток-отправитель :
while not PostThreadMessage() do ..
поток-получатель же должен сразу после старта как можно быстрее вызвать любую из ф-ций, отвечающих за выборку сообщений из очереди (при первом же вызове очередь будет создана), например :
PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE)
← →
snake1977 (2004-01-15 12:44) [41]>>Digitman ©
объясняю почему не Timer который запускает Thread. Программа посотренна таким образм: есть главный модуль который запускает процедуры из прописанных в его настройках DLL модулях. Каждая из запускаемых процедур отвечает только за свою фунукцию, например одна прослушивает сокет и получая сообщение записывает его в файл, другая просмотривает диск на наличие файлов определнного вида, найдя открывает и обрабатывает выкладывая результат в другой файл. третья просмотривает файлы ответов и отправляет его через сокет :) вот примерно так. Количество таких модулей заранее не известно и период срабатывания каждой из процедур также может быть различен. при всем при этом естесвтенно что модуль овечающий за например прослушивание сокета не как не связан и не джолжен мешать работе модуля обрабатывающего файлы. вот по тому и надо сделать паралельное функционирование различных модулей , которые обрабатывают информацию в различные периоды времени
← →
Dred2k (2004-01-15 12:52) [42]> Digitman © (15.01.04 12:40) [40]
> поток ответственен за выборку сообщений
> здесь имелось ввиду
"в любом случае" - оставляет не слишком много вариантов. Теперь понятно.
> поэтому одним из грамотных подходов к реализации корректной
логики является следующий ...
Я бы сказал, что это не "грамотный подход", а однозначно документированные требования.
← →
Nikolay M. (2004-01-15 12:53) [43]
> snake1977 (15.01.04 12:44) [41]
Не влезая в суть разбирательств, обращаю внимание на [36] и рекомендую еще посмотреть TRxTimerList. Хотя это дело хозяйское.
← →
Verg (2004-01-15 12:54) [44]
> snake1977 (15.01.04 12:44) [41]
Все понятно, непонятно для чего в этих потоках тебе TTimer, т.е. этот компонент именно?
Для отсчета таймаутов и безо всяких TTimer хватает средств.
← →
Digitman (2004-01-15 12:55) [45]
> snake1977 (15.01.04 12:44) [41]
кинь на форму один-единственный TTimer, установи нужный период срабатывания
в обработчике OnTimer() создавай один или более объектов-наследников TThread, метод Execute каждого из которых будет заниматься своим делом и никак не будет мешать иным потокам
осн.потоку остается только при каждом тике таймера проверять состояние завершенности тех или иных потоков, чтобы не создавать лишние
← →
Digitman (2004-01-15 12:57) [46]
> Dred2k © (15.01.04 12:52) [42]
> Я бы сказал, что это не "грамотный подход", а однозначно
> документированные требования.
поэтому, очевидно, и грамотный.
непонятно только зачем ты цитировал хэлп - мне это известно не хуже тебя
← →
Dred2k (2004-01-15 13:00) [47]По-моему, тут проще можно. Передаем в нитку при создании отправное значение GetTickCount (для синхронизации) и расписание срабатываний. Далее поток просто считает тики и сверяет с расписанием, когда нужно - срабатывает.
← →
Verg (2004-01-15 13:03) [48]
> Digitman © (15.01.04 12:55) [45]
>
> > snake1977 (15.01.04 12:44) [41]
>
>
> кинь на форму один-единственный TTimer, установи нужный
> период срабатывания
>
> в обработчике OnTimer() создавай один или более объектов-наследников
> TThread, метод Execute каждого из которых будет заниматься
> своим делом и никак не будет мешать иным потокам
А что, без таймера никак нельзя запустить несколько кодовых потоков, каждый из которых вызовет нужную свою ф-цию из DLL?
← →
Dred2k (2004-01-15 13:06) [49]> Digitman © (15.01.04 12:57) [46]
> непонятно только зачем ты цитировал хэлп - мне это известно
не хуже тебя
Это хорошо. Молодец.
P.S.
А действительно - с какого такого перепоя я вдруг без высочайшего разрешения позволил себе процитировать ВАМ (простиТЕ, большЕЕ буковок нет) хелп.
Непозволительная грубость. Исключительный цинизмъ.
P.P.S.
Все хорошо в меру. В том числе и жажда научить.
← →
Digitman (2004-01-15 13:08) [50]
> Verg © (15.01.04 13:03) [48]
а я почем знаю ? я именно так понял задачу автора из его слишком общих и не совсем терминологически корректных объяснений
все зависит от
> которые обрабатывают информацию в различные периоды времени
что за периоды, как они связаны с центральной логикой управления потоками - мне не понятно на сей момент из вышеизложенного
← →
Verg (2004-01-15 13:09) [51]
> Далее поток просто считает тики и сверяет с расписанием,
> когда нужно - срабатывает.
Я че-то не пойму - где в ТЗ (snake1977 (15.01.04 12:44) [41] ) :) упоминание о каких-либо "расписаниях" ?
Там явно написано, что потоки должны быть независимы и выполняться одновремено
← →
Digitman (2004-01-15 13:09) [52]
> Dred2k © (15.01.04 13:06) [49]
без комментариев
← →
Verg (2004-01-15 13:16) [53]
> обрабатывают информацию в различные периоды времени
По-моему, это "переводится", как "Обрабатывают информацию за различное время"
Т.е. одна ф-ция может управится со своей работой за 1 сек, а другой и 5-ти минут может не хватить.
← →
Digitman (2004-01-15 13:20) [54]
> Verg © (15.01.04 13:16) [53]
нет, мне здесь иное не понятно - то ли планирование запуска должно быть реализовано с учетом некоего центрального расписания (которое вполне могло быть у автора реализовано и в осн.потоке), то ли осн.поток сразу стартует N доп.потоков и за сим успокаивается (потоки же после старта сами реализуют индивидуальные расписания), то ли и сами потоки запускаются по расписанию и затем реализуют внутри себя еще и собственные расписания ...
← →
y-soft (2004-01-15 13:22) [55]А почему обязательно Timer? Штука это низкоприоритетная и не слишком точная. Sleep надежен, но тоже неточен.
Хорошее и простое решение получается с WaitableTimer, причем можно вынести его обработку в отдельный поток с тем, чтобы он периодически будил остальные потоки...
← →
Dred2k (2004-01-15 13:34) [56]> Verg © (15.01.04 13:09) [51]
> snake1977 (15.01.04 12:44) [41]
которые обрабатывают информацию в различные периоды времени
то ли имеется в виду параллельность работы, то ли некие конкретные периоды между выполнением прикладных дейтсвий. Надеюсь, будут пояснения.
← →
Digitman (2004-01-15 13:41) [57]если требуется некая универсальность, дабы не плодить кучу классов-наследников TThread, можно реализовать единственного наследника, в теле Execute которого запустить цикл выборки/диспетчеризации сообщений :
while not Terminated and GetMessage(Msg, 0, 0 0) do
if Msg.hWnd = 0 then
Dispatch(Msg.message) //обработка сообщений данному потоку
else
DispatchMessage(Msg); //обработка сообщений окнам, потенциально создаваемым в контексте данного потока
теперь некий поток-координатор (пусть это будет осн.поток) в соответствии с событиями некоего расписания запуска неких п/программ (неважно где находящихся, лишь бы в тек. ВАП их тела были) посылает сообщение первому же найденному потоку, свободному от обработки предыд.сообщений, сообщение с параметрами, указывающими на адрес п/программы, которую следует запустить в контексте найденного потока, и параметрами, которые следует передать этой п/программе при ее вызове
← →
gaa (2004-01-15 17:06) [58]constructor TWaitableTimer.Create(Name: PAnsiChar = nil);
begin
FTimerHandle:= CreateWaitableTimer(nil,True,Name);
FEnabled:= False;
FDueTime:= WT_MSec;
FResume:= False;
FPeriod:= wtpPeriod;
FTimerContext:= nil;
FName:= Name;
// OpenWaitableTimer($1F0003,False,Name)
end;
Страницы: 1 2 вся ветка
Форум: "Основная";
Текущий архив: 2004.01.29;
Скачать: [xml.tar.bz2];
Память: 0.61 MB
Время: 0.008 c