Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
14-93694
Layner
2004-01-06 11:12
2004.01.29
А кому Майкла Джексона жаль?


3-93367
Danilas
2004-01-02 16:32
2004.01.29
Как создать генератор в InterBase


1-93420
jiurajhgjhgty
2004-01-16 19:53
2004.01.29
OleContainer и excel


3-93380
sashok
2003-12-30 11:12
2004.01.29
Локальные базы данных


7-93702
msgipss
2003-11-14 11:17
2004.01.29
Как программно настроить аудит на конкретный файл





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