Форум по Delphi программированию



Вернуться   Форум по Delphi программированию > Все о Delphi > ОС и железо
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 11.08.2015, 15:16
Yes_Maks Yes_Maks вне форума
Прохожий
 
Регистрация: 22.07.2014
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Грамотно организовать поток для отлова событий COM порта

Уважаемые форумчане, всем добрый день! Подскажите путь решения. Ситуация следующая. Пишу приложение на delphi7, которое через ком порт общается с устройствами в сети (до 255 устройств может быть). Пользуюсь компонентом-библиотекой для работы с ком-портом ComPort Library 4.10 от Dejan Crnila. Приложение сначала сделал однопоточное, ибо программка большую часть времени простаивает и ждет пакет, приходящий в ком порт от любого из устройств. События прихода данных в ком порт отслеживаются и обрабатываются процедурой onRxChar, которая является частью класса этой самой библиотеки. В этой процедуре-обработчике выполняется вся обработка поступивших пакетов, вся реакция на них. Все бы было хорошо, если бы не 2 нюанса.
1. Иногда из сети от устройства может прийти пакет, который должен "усыпить" программу на определенное время. Усыпление я делаю с помощью вызова модального окна без кнопки закрыть его, а только с предупреждением о том, что программа временно приостановлена. (Такой способ приемлем или можно как-то более красиво?):
Код:
procedure TF_Main.ComPort1RxChar(Sender: TObject; Count: Integer);
begin
  ComPort1.Read(P_vhod,15);
  If (P_vhod[9]=1) and (P_vhod[10]=2) and (P_vhod[12]=20)//Если пришел пакет на "засыпание" программы
    then
      begin
        FWait:= TFWait.Create(Self);
        FWait.ShowModal;
      end;
  if (P_vhod[9]=1) and (P_vhod[10]=2) and (P_vhod[12]=21)//Программе надо проснуться
    then
      FWait.Close;
...
еще много других реакций
...

Но когда запущено модальное окно, управление не переходит на прием следующего пакета, который выведет программу
из спящего состояния, а все выполнение останавливается на строчке FWait.ShowModal. Типа программа зависла.
2.В программе есть кнопка опроса устройств и отправки данных на устройства. В обработчике кнопки "опросить" запускается цикл от 1 до 255 каждые 50 мс по 3 раза на каждое устройство (765 итераций). Цикл длится примерно 40 секунд. В цикле я отправил пакет на устройство 1. Оно ответило пакетом. Этот пакет пришел в порт, НО обработчик ComPort1RxChar НЕ может пока сработать, ибо сейчас выполняется обработчик нажатия кнопки и выполняется цикл. Первое устройство ответило, мы не обработали пакет, второе ответило, мы не обработали....Я так понимаю, пока размера буфера хватает, эти байты там сохраняются. После окончания цикла мы, может быть, сможем обработать первые 10-15 пакетов с первых 10-15 устройств. И пропустим почти все пришедшие пакеты с остальных устройств. А если еще вдруг в процессе опроса придет пакет на засыпание программы. Мы его тоже можем не отловить получается. Я решил по нажатии кнопки "опросить" запустить дополнительный поток, слушающий ком порт:
Код:
procedure TF_Main.Btn_SchitSoStellyClick(Sender: TObject);
var
  i,t:integer;
begin
...
  T1:= ToolkPort.Create(false);
  T1.FreeOnTerminate:= True;

Но в самом потоке не знаю, как вызвать процедуру из основного потока, что бы она продолжала слушать ком порт и обрабатывать пакеты, а в случае чего еще и приостанавливать поток основной программы и выводить модальное окно с предупреждением? и Так же в потоке ловить пакет выхода из спячки и убирать модальное окно
Код:
unit U_PortToolk;
interface
uses
  Classes, CPortCtl, ExtCtrls, CPort, Dialogs, Windows, Messages,
  SysUtils, Formirovatel_Paketov, U_StopModal;

type
  ToolkPort = class(TThread)
  ComPort: TComPort;

  private
    
  protected
    procedure Execute; override;
  end;

implementation

uses
  U_Main;

procedure ToolkPort.Execute;
begin
  {Вот здесь не знаю как правильно вызвать обработчик TF_Main.ComPort1RxChar, чтобы и в цикле он реагировал 
    на приходящие пакеты}
  until Terminated;
end;

end.

Что в Execute потока прописать, что бы корректно все работало? Не заново же дублировать весь код обработчика TF_Main.ComPort1RxChar...

Спасибо всем кто откликнется
Ответить с цитированием
  #2  
Старый 12.08.2015, 02:27
Аватар для Verevkin
Verevkin Verevkin вне форума
Прохожий
 
Регистрация: 22.06.2015
Адрес: 1600, пенсильвания-авеню, п.г.т. верхний Вашингтонск, 8126 км от МКАД, от поста ГАИ - налево.
Сообщения: 40
Версия Delphi: 3...XE10
Репутация: -50
По умолчанию

1. всю работу с портом вынести в левый тред.
2. выкинуть нафиг модальное окно.
3. прогу не усыплять, а устанавливать флаг "прога_спит" и продолжать слушать порт в ожидании сообщения "проснуться", игнорив остальные.
4. по принятию "проснуться" просто сбрасывать флаг "прога_спит" и всё.
Ответить с цитированием
  #3  
Старый 12.08.2015, 09:03
Yes_Maks Yes_Maks вне форума
Прохожий
 
Регистрация: 22.07.2014
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Verevkin
1. всю работу с портом вынести в левый тред.
2. выкинуть нафиг модальное окно.
3. прогу не усыплять, а устанавливать флаг "прога_спит" и продолжать слушать порт в ожидании сообщения "проснуться", игнорив остальные.
4. по принятию "проснуться" просто сбрасывать флаг "прога_спит" и всё.

Что нужно сделать с потоком, когда установлен флаг "прога_спит"?) Мне конкретно нужно, что бы главное окно во время засыпания проги не реагировало на нажатие клавиш пользователя. Каким образом лучше всего тогда приостановить поток в тот момент, когда в порт придет команда на остановку проги?

И в левом треде тогда что, все время крутить бесконечный цикл?
Код:
repeat
    ComPort.Read(P_vhod,15);
   ....
    Разлчные действия
   ...
  until Terminated;
Ответить с цитированием
  #4  
Старый 13.08.2015, 01:30
Аватар для Verevkin
Verevkin Verevkin вне форума
Прохожий
 
Регистрация: 22.06.2015
Адрес: 1600, пенсильвания-авеню, п.г.т. верхний Вашингтонск, 8126 км от МКАД, от поста ГАИ - налево.
Сообщения: 40
Версия Delphi: 3...XE10
Репутация: -50
По умолчанию

Цитата:
Мне конкретно нужно, что бы главное окно во время засыпания проги не реагировало на нажатие клавиш пользователя.
не делай так! оставь пользователю право рулить прогой всегда, а не только убивать процесс из диспетчера.
Цитата:
И в левом треде тогда что, все время крутить бесконечный цикл?
именно так. в этом и весь принцип многопоточности.
Ответить с цитированием
  #5  
Старый 13.08.2015, 15:44
Yes_Maks Yes_Maks вне форума
Прохожий
 
Регистрация: 22.07.2014
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Verevkin
именно так. в этом и весь принцип многопоточности.
Дополнительный поток на 30% загружает процессор?
Это нормально?
Ответить с цитированием
  #6  
Старый 13.08.2015, 16:00
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,503
Версия Delphi: XE10
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Yes_Maks
Дополнительный поток на 30% загружает процессор?
Это нормально?
Нет, тот оратор долпайоп. Поток должен выполнять задач(у/и), а не крутить цикл.
Есть такое понятие: задача. Задача должна быть быстрой и может выполняться в любом свободном потоке, который может выделить пул потоков. Задача может сама себя по новой поставить в очередь задач.
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
  #7  
Старый 13.08.2015, 16:28
Yes_Maks Yes_Maks вне форума
Прохожий
 
Регистрация: 22.07.2014
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от M.A.D.M.A.N.
Есть такое понятие: задача. Задача должна быть быстрой и может выполняться в любом свободном потоке, который может выделить пул потоков. Задача может сама себя по новой поставить в очередь задач.
Как это в делфи осуществить? Есть пример кода или где почитать, чтобы более менее понятно было?
Ответить с цитированием
  #8  
Старый 14.08.2015, 01:10
Аватар для Verevkin
Verevkin Verevkin вне форума
Прохожий
 
Регистрация: 22.06.2015
Адрес: 1600, пенсильвания-авеню, п.г.т. верхний Вашингтонск, 8126 км от МКАД, от поста ГАИ - налево.
Сообщения: 40
Версия Delphi: 3...XE10
Репутация: -50
По умолчанию

Цитата:
Сообщение от Yes_Maks
Дополнительный поток на 30% загружает процессор?
Это нормально?
если он слушает порт, то, конечно нет!
Ответить с цитированием
  #9  
Старый 31.08.2015, 14:52
Yes_Maks Yes_Maks вне форума
Прохожий
 
Регистрация: 22.07.2014
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Народ, тема не закрыта. Помогите советом пожалуйста. Почитав статей и книг по организации работы с com портом в параллельном потоке, все сходятся на мысли что поток чтения данных с ком порта надо делать так:
Код:
...
procedure COM_Thread.Execute;
begin
  While not Terminated do
    begin
      If not WaitCommEvent(hCOM,TMask,@Ovr) then
      if GetLastError = ERROR_IO_PENDING  then
        WaitForSingleObject(Ovr.hEvent, INFINITE);//Ожидаем приема до бесконечности
      ClearCommError(hCOM,xn,@StatCOM);//Получаем состояние порта в StatCOM
      xn:= StatCOM.cbInQue;//Реальное количество байт в буфере
      If xn>0 then
        If ReadFile(hCOM,paket,xn,xn,@ovr) then
          SendMessage(Form1.Handle,wmCOM,1,0);
    end;
end;
Я собственно так же и сделал. В основном потоке порт открываю естественно с флагом FILE_FLAG_OVERLAPPED, устанавливаю событие-маску
Код:
Ovr.hEvent:= CreateEvent(nil,True,False,nil)
, где Ovr и есть структура оверлаппинга TOverlapped.
Все хорошо, но только тогда, когда приложение ничего не делает и только ждет каких то данных от порта. Тогда да, пакет пришел в порт, дополнительный поток его принял, обработал, отправил сообщение главному окну, в главном потоке сообщение обработалось.
Но у меня приложение регулярно в цикле опрашивает 255 устройств. Опрос идет из главного потока. Там я пишу в порт
Код:
WriteFile(hCOM,paket,15,xn,@Ovr);

Так вот, когда идет последовательный опрос, с устройств тут же приходит пакет-ответ. НО дополнительный поток НЕ обрабатывает эти пакеты, пока не прогонится весь цикл. А когда цикл прогонится, обрабатывается всего лишь один или два пакета, которые остались в буфере. остальное пропадает. Подскажите как сделать синхронизацию между потоками грамотно и можно ли это сделать в делфи7 вообще?
Ответить с цитированием
Ответ



Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 19:23.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2021

ВКонтакте   Facebook   Twitter   Ссылка на Telegram