Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Работа с потоками [D6, Win95/98, WinXP]


Страницы:   1 2

Izyum ©   (2004-10-14 16:18:00) 

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

ВОПРОС: это так и должно быть или есть способ создать вторичный поток, который работает абсолютно независимо от главного?


Izyum   (2004-10-18 14:34:00) [1]

Нет, это не прерывания... Было бы наверно проще с ними иметь дело, но не подходят они... 376h - альтернативный регистр состояния НЖМД второго канала...
В принципе я уже начал "копать" другой путь решения...

Но все равно, ВСЕМ спасибо


Erik1   (2004-10-18 14:29:00) [2]

Нет, в даном случае WaitForMultipleObjects тлько для ожидания потоком команды на выполнение и остановку. Для IO портов невозможно использование WaitFor функций.
 Похоже, что действительно не тем путем. Если через порт 376h поступают данные, то надо записывать их в кукой то буфер и по завершению активности посылать сообшение. Еще можно записавать в PIPE а в гланом потоке проверять переменую указывающею размер буфера.
 Но все это както странно, может ты обрабатываеш какоето прерывание? Вобще програмирование на апаратном уровне сильно отличается.


Izyum   (2004-10-18 11:58:00) [3]

Erik1 ©   (18.10.04 10:14) [24]

Спасибки, попробую разобраться с кодом...
Вторичный поток должен "слушать" порт 376h, данные в котором могут меняться ОЧЕНЬ интенсивно в один момент, а в другой быть совершенно неизменными...

Но, похоже, я изначально не тем путем пошел...
ЗЫ: Вышеприведенный код как раз и является реализацией использования WaitForMultipleObjects при мониторинге ЛЮБОГО порта?


Erik1   (2004-10-18 10:14:00) [4]

А в InternalExec свой цикл делай, только добавь в него Sleep(5) или сколько ты можеш себе позволить. Можно эксперементально определить с какой минимальной частотой у тебя изменяются данные. Также добавь проверку на состояние события.
 По приходу данных из порта ненадо их сразу окну отпралять, наверное генерируется огромное число сообщений. Тут разяснение требуется, что это за данные и для чего они нужны.


Erik1   (2004-10-18 10:07:00) [5]

Если работаеш с IO то конечно все самому придется делать. Использовать можно так:
type
 TActiveEvent = (actExit, actSend);
 RAction = record
   Event: array[TActiveEvent] of THandle;
   Call: array[TActiveEvent] of TNotifyEvent;
 end;
 PAction = ^RAction;
...
procedure TCustomThread.CreateEvent;
var
 i: TActiveEvent;
begin
 for i := Low(tmEvent.Event) to High(tmEvent.Event) do
 begin
   tmEvent.Event[i] := Windows.CreateEvent(nil, false, false, nil);
 end;
end;

constructor TCustomThread.Create(TimeOut: Integer);
begin
 inherited Create(True);
 fTimeOut := INFINITE;

 fID := Random(MaxInt);
 fActive := False;
 tmEvent.Call[actSend] := InternalExec;
 tmEvent.Call[actExit] := BreakThread;
 CreateEvent;
end;

procedure TCustomThread.Execute;
var
 Status: DWord;
label
 Retry;
begin
 Retry:
 Status := WaitForMultipleObjects(Ord(High(tmEvent.Event)) + 1, @tmEvent.Event,
   false, fTimeOut); //INFINITE

 if fActive and (TActiveEvent(Status) <> actExit) then
   exit;

 fActive := True;
 try
   try
     case Status of
       Ord(Low(TActiveEvent))..Ord(High(TActiveEvent)):
       begin
         tmEvent.Call[TActiveEvent(Status)](Self);
         if (TActiveEvent(Status) <> actExit) then
           Synchronize(DoFinished);
       end;
     else
       if Status = WAIT_TIMEOUT then
         WaitTimeOut;
     end;
   except
     InternalException;
   end;
 finally
   FActive := False;
 end;

 if not Terminated then
   goto Retry;
end;
Это общая заготовка.


panov   (2004-10-18 10:06:00) [6]

>Izyum ©   (18.10.04 09:10) [21]
Не надо столько сообщений много посылать.

Кстати, сообщения обрабатываются, даже если "...взять за заголовок и достаточно долго подержать мышкой..."


Izyum   (2004-10-18 09:10:00) [7]

Такс, передача результатов через сообщения помогло - вторичный поток не засыпает... Но тут вылезли другие проблемы: если главную форму взять за заголовок и достаточно долго подержать мышкой - приложение начисто зависает... При попытке снять его через три волшебных кнопки выдается сообщение "Системе существенно не хватает ресурсов"... Я так понял - очередь сообщения не резиновая и сколько угодно в нее не поместится необработанных сообщений...

С этим как-то бороться можно или надо изначально по другому пути идти?


Defunct   (2004-10-15 20:04:00) [8]

Zelius ©   (15.10.04 11:48) [16]
Завсит от стадии "готовности" программы и от того как спроектирована программа. Если функции вывода уже готовы, то лучше использовать доп. поток (меньше изменений в программе).


Izyum   (2004-10-15 14:33:00) [9]

Erik1 ©   (15.10.04 12:04) [17]
>>Если чтото другое то что за порт если не секрет(надеюсь не IO)?
Совершенно верно - IO:)))


Izyum   (2004-10-15 12:27:00) [10]

Ну это уже детали...
Мне нужно в общем-то опрашивать порт 123h и при изменении данных в нем гарантировано записать что-то при выполнении определнного условия в порт 456h, и паралельно отобразить это на экране, если таковая возможность в данный момент времени имеется...

При такой постановке вопроса нужно использовать ПОСТОЯННЫЙ (в цикле) опрос порта, или можно как-то использовать WaitForSingleObject???


Erik1   (2004-10-15 12:04:00) [11]

"Или WaitForSingleObject можно использовать при работе с ЛЮБЫМ портом?" Да именно с любым! И еще SetComMask никак несвязана с overlaped. Использование overlaped предпологает наличие аснихроного режима работы без нагрузки на процесор. По com порту могбы дать конкретные рекомендации или готовый компонент. Если чтото другое то что за порт если не секрет(надеюсь не IO)?


Zelius   (2004-10-15 11:48:00) [12]

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


Izyum   (2004-10-15 11:22:00) [13]

Erik1 ©   (15.10.04 10:26) [14]

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

Или WaitForSingleObject можно использовать при работе с ЛЮБЫМ портом?


Erik1   (2004-10-15 10:26:00) [14]

А вобщето бери готорый компонент на Torry.net и немайся дурью. Тебе хороший коипонент еще несколько лет писать. Смотри чтобы подерживал overlaped.


Izyum   (2004-10-15 08:56:00) [15]

Defunct ©   (14.10.04 22:12) [12]
Сенкс


Defunct   (2004-10-14 22:12:00) [16]

[11]

TReportSyncThread взят из рабочего проекта. Там помимо вывода информации в Memo, предусмотрено выполнение TNotifyEvent и процедур работающих с визуальными компонентами (см. конструкторы). Таким образом вопросом синхронизации с основыным потоком занимается исключительно TReportSyncThread, ну а ваш поток работает без приостановок.


Defunct   (2004-10-14 21:59:00) [17]

> А чуть более развернуто можно?:)

Можно. Я сразу приведу пример.

Допустим есть критический к приостанову поток, который работает в RealTime (RT) и не должен пропустить ни одной порции данных поступающей на порт X. В то же время требуется выводить какую-то информацию для отчета в Memo. Реализация: создается доп. поток, задачей которого будет вывод в какой-то строки в Memo. После вывода этот поток автоматически удаляется:

     TJob = Procedure of object;
     TReportJob = Procedure(Msg: String) of object;

     TReportSyncThread = class(TThread)
     Private
       FJob         : TJob;
       FReportJob   : TReportJob;
       FMsg         : String;
       FSender      : TObject;
       FNotifyEvent : TNotifyEvent;
       Procedure DoReport;
       Procedure DoJob;
       Procedure DoNotifyEvent;
     Protected
       procedure Execute; override;
     Public
       Constructor Create(AJob:TJob);
       Constructor CreateNotifyEvent(Sender:TObject; ANotifyEvent:TNotifyEvent);
       Constructor PostMessage(AMsg:String;AReportJob:TReportJob);
     End;

{******************************************}
{********** Report Sync Thread ************}
{******************************************}
Constructor TReportSyncThread.Create;
Begin
 If Assigned(AJob) Then
 Begin
   FJob := AJob;
   FreeOnTerminate := True;
   Inherited Create(False);
   Priority := tpNormal;
 End;
End;

Constructor TReportSyncThread.CreateNotifyEvent;
Begin
 If Assigned(ANotifyEvent) Then
 Begin
   FNotifyEvent := ANotifyEvent;
   FSender := Sender;
   FreeOnTerminate := True;
   Inherited Create(False);
   Priority := tpNormal;
 End;
End;

Constructor TReportSyncThread.PostMessage;
Begin
 If Assigned(AReportJob) Then
 Begin
   FReportJob := AReportJob;
   FMsg := AMsg;
   FreeOnTerminate := True;
   Inherited Create(False);
   Priority := tpNormal;
 End;
End;

Procedure TReportSyncThread.DoReport;
Begin
 If Assigned( FReportJob ) Then FReportJob(FMsg);
End;

Procedure TReportSyncThread.DoJob;
Begin
 If Assigned(FJob) Then FJob;
End;

Procedure TReportSyncThread.DoNotifyEvent;
Begin
 If Assigned(FNotifyEvent) Then FNotifyEvent(FSender);
End;

Procedure TReportSyncThread.Execute;
Begin
 Synchronize(DoJob);
 Synchronize(DoReport);
 Synchronize(DoNotifyEvent);
End;

{********************************************}


Вывод информации в вашем потоке можно сделать например так:

Procedure TMyThread.SyncReport(Msg:String);
Begin
 If Assigned(FMemo) Then
 Try
   FMemo.Lines.Add(Msg);
 Except
 End;
End;

Procedure TMyThread.Report(Msg: String);
Begin
 If Not Terminated Then
  TReportSyncThread.PostMessage(Msg, SyncReport);
End;

Procedure TMyThread.Execute;
Var I:Integer;
Begin
 I := 0;
 While not Terminated Do
 Begin
   // Ждем данных с  порта

   Inc(i);
   Report('Прочитали порцию '+IntToStr(I)); // Вывод какой-то
инфы
 End;
End;


Izyum   (2004-10-14 18:06:00) [18]

Defunct ©   (14.10.04 17:38) [8]
А чуть более развернуто можно?:)


Izyum   (2004-10-14 17:38:00) [19]

Александр, спасибо за пинок в нужную сторону - я про эту возможность совсем позабыл:)


Defunct   (2004-10-14 17:38:00) [20]

Izyum ©   (14.10.04 17:28) [6]
> Тогда может кто-то подскажет как реализовать такую задачу:
во вторичном потоке необходимо ГАРАНТИРОВАНО считывать данные из какого-либо порта (давайте для примера возьмем COM)и по возможности отображать результаты на главной форме.


Создавать еще один поток для синхронизации вывода.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо