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

Delphi Sources



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

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 21.10.2013, 11:10
Smallboy Smallboy вне форума
Прохожий
 
Регистрация: 16.07.2013
Сообщения: 18
Версия Delphi: Delphi XE4
Репутация: 10
По умолчанию Реализация параллельной работы

Доброе утро!
У меня возник вопрос. Пару месяцев назад начал работать с делфи.
Подскажите как реализовать следующую задачу.

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

Запрос представляет из себя строку с параметрами. Получив эти параметры программа вызывает функцию из Dll,
которая отправляет эти параметры на устройство через COM- порт. Устройство обрабатывает данные и возвращает ответ.

Суть проблемы. Обработка данных устройством занимает 15-20 секунд, и в это время все запросы приходящие на порт, который слушается -- становятся в очередь и не обрабатываются пока не отработает функция. Это не допустимо. Необходимо, чтобы в случае занятости -- клиент сразу получал ответ. Как наладить параллельную работу
прослушки порта и остальной работы программы?

Вот участок кода, который обрабатывает запросы:

Код:
if ServerSocket.Socket.ActiveConnections = 1 then
    begin
       //тут читаем параметры запроса
      CheckRequest; // обрабатывает запрос (15-20 секунд);
      GetParam:='';
      exit;
    end
    else
    begin
      ServerSocket.Socket.Connections[ServerSocket.Socket.ActiveConnections-1].SendText('Сервер не доступен');
      Application.ProcessMessages;
      Buffer.Lines.Insert(0,'Отключаем лишний коннект');
      Application.ProcessMessages;
      ServerSocket.Socket.Connections[ServerSocket.Socket.ActiveConnections-1].Close;
      Application.ProcessMessages;
      ConNum;
    end;
Ответить с цитированием
  #2  
Старый 21.10.2013, 11:24
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

завести флаг занятости устройства. устанавливать его при получении запроса от клиента и сбрасывать после получения ответа от устройства. в обработчике запросов от клиентов проверять флаг занятости и отвергать запросы (сообщать клиенту о занятости) при его активности.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #3  
Старый 21.10.2013, 11:25
Аватар для Aristarh Dark
Aristarh Dark Aristarh Dark вне форума
Модератор
 
Регистрация: 07.10.2005
Адрес: Москва
Сообщения: 2,907
Версия Delphi: Delphi XE
Репутация: выкл
По умолчанию

...ну и конечно CheckRequest обрабатывать в отдельном потоке.
__________________
Некоторые программисты настолько ленивы, что сразу пишут рабочий код.

Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты.
Ответить с цитированием
  #4  
Старый 21.10.2013, 11:36
Smallboy Smallboy вне форума
Прохожий
 
Регистрация: 16.07.2013
Сообщения: 18
Версия Delphi: Delphi XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
завести флаг занятости устройства. устанавливать его при получении запроса от клиента и сбрасывать после получения ответа от устройства. в обработчике запросов от клиентов проверять флаг занятости и отвергать запросы (сообщать клиенту о занятости) при его активности.


Это у меня все реализовано. Флагом является проверка на уже существующий коннект. Если он есть, то все остальные запросы получают ответ о занятости устройства.

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

Цитата:
Сообщение от Aristarh Dark
...ну и конечно CheckRequest обрабатывать в отдельном потоке.

Я только начал читать про потоки.
Подскажите пожалуйста основные моменты, как в моем случае это реализовать

Последний раз редактировалось M.A.D.M.A.N., 21.10.2013 в 15:15.
Ответить с цитированием
  #5  
Старый 21.10.2013, 12:29
Аватар для Aristarh Dark
Aristarh Dark Aristarh Dark вне форума
Модератор
 
Регистрация: 07.10.2005
Адрес: Москва
Сообщения: 2,907
Версия Delphi: Delphi XE
Репутация: выкл
По умолчанию

Предроложим что:
BusyFlag - глобальная переменная в рамках данного модуля
TCheckRequestThread - поток который обрабатывает запрос на внешнем устройстве, после обработки данных он самоуничтожается.
Код:
if ServerSocket.Socket.ActiveConnections = 1 then
    begin
       //тут читаем параметры запроса
      if not BusyFlag then
        begin
          BusyFlag:=True;
          TCheckRequestThread.Create;   //запускаем поток (возможно, и даже скорее всего,
// в конструктор нужно быдет передать некоторые параметры)
//          CheckRequest; // обрабатывает запрос (15-20 секунд);
        end
      else
        begin
          //тут отклоняем запросы пользователей
        end; 
      GetParam:='';
      exit;
    end
    else
    begin
      ServerSocket.Socket.Connections[ServerSocket.Socket.ActiveConnections-1].SendText('Сервер не доступен');
      Application.ProcessMessages;
      Buffer.Lines.Insert(0,'Отключаем лишний коннект');
      Application.ProcessMessages;
      ServerSocket.Socket.Connections[ServerSocket.Socket.ActiveConnections-1].Close;
      Application.ProcessMessages;
      ConNum;
    end;
на событие OnTerminate потока вешаешь обработчик который отправляет результаты обработки данных нужному пользователю и снимает BusyFlag
__________________
Некоторые программисты настолько ленивы, что сразу пишут рабочий код.

Если вас наказали ни за что - радуйтесь: вы ни в чем не виноваты.
Ответить с цитированием
  #6  
Старый 21.10.2013, 13:00
Smallboy Smallboy вне форума
Прохожий
 
Регистрация: 16.07.2013
Сообщения: 18
Версия Delphi: Delphi XE4
Репутация: 10
По умолчанию

Цитата:
Сообщение от Aristarh Dark
Предроложим что:
BusyFlag - глобальная переменная в рамках данного модуля
TCheckRequestThread - поток который обрабатывает запрос на внешнем устройстве, после обработки данных он самоуничтожается.
Код:
if ServerSocket.Socket.ActiveConnections = 1 then
    begin
       //тут читаем параметры запроса
      if not BusyFlag then
        begin
          BusyFlag:=True;
          TCheckRequestThread.Create;   //запускаем поток (возможно, и даже скорее всего,
// в конструктор нужно быдет передать некоторые параметры)
//          CheckRequest; // обрабатывает запрос (15-20 секунд);
        end
      else
        begin
          //тут отклоняем запросы пользователей
        end; 
      GetParam:='';
      exit;
    end
    else
    begin
      ServerSocket.Socket.Connections[ServerSocket.Socket.ActiveConnections-1].SendText('Сервер не доступен');
      Application.ProcessMessages;
      Buffer.Lines.Insert(0,'Отключаем лишний коннект');
      Application.ProcessMessages;
      ServerSocket.Socket.Connections[ServerSocket.Socket.ActiveConnections-1].Close;
      Application.ProcessMessages;
      ConNum;
    end;
на событие OnTerminate потока вешаешь обработчик который отправляет результаты обработки данных нужному пользователю и снимает BusyFlag


Понял. Спасибо попробую. Сейчас читаю про потоки. Возник вопрос:

Вот стандартный пример для обращения из потока к свойствам vcl компонент
Код:
procedure MyThread.UpdateCaption;
begin
  Form1.Caption := 'Updated in a thread';
end;

procedure MyThread.Execute;
begin
  Synchronize(UpdateCaption);
end;

возможно ли через процедуру Synchronize обращаться напрямую к процедурам объекта TForm

например есть вот такое
Код:
procedure TForm1.UpdateCaption;
begin
  Caption := 'Updated in a thread';
end;

как можно вызвать эту процедуру в потоке? Это будет верно?
Код:
procedure MyThread.Execute;
begin
  Synchronize(TForm1.UpdateCaption);
end;

Последний раз редактировалось M.A.D.M.A.N., 22.10.2013 в 09:48.
Ответить с цитированием
  #7  
Старый 21.10.2013, 13:06
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
Сообщение от Smallboy
пока не отработает функция с COM портом
так, наверное, работа с портом в синхронном режиме идет и в основном потоке
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #8  
Старый 21.10.2013, 14:45
Smallboy Smallboy вне форума
Прохожий
 
Регистрация: 16.07.2013
Сообщения: 18
Версия Delphi: Delphi XE4
Репутация: 10
По умолчанию

подскажите можно ли из потока вызвать функцию(из длл).
Функция описана так в TForm:
и как это правильно сделать.
Код:
private
   SetComParams : function(Num: Byte; Rate: DWord): Byte; stdcall;

Последний раз редактировалось M.A.D.M.A.N., 22.10.2013 в 09:48.
Ответить с цитированием
  #9  
Старый 21.10.2013, 16:23
Sibay Sibay вне форума
Прохожий
 
Регистрация: 21.10.2013
Сообщения: 5
Версия Delphi: Delphi XE5
Репутация: 10
По умолчанию

Так вызывать нельзя - метод должен быть описан внутри класса потока. Вызывай свой CheckRequest в MyThread.Execute; В твоем случае отсутствие синхронизации не приведет к сбою. Естественно CheckRequest должен быть описан в классе TMyThread.
Установи свойство MyThread.FreeOnTerminate в true. Флаг использовать не обязательно, достаточно проверить является ли MyThread nil. Если поток выполняется, то отвечай клиенту, что "занято", если поток nil, то создавай поток и запускай его (Resume).

Рекомендую почитать про потоки и методы синхронизации подробнее.

Последний раз редактировалось Sibay, 21.10.2013 в 16:26.
Ответить с цитированием
  #10  
Старый 21.10.2013, 16:36
Smallboy Smallboy вне форума
Прохожий
 
Регистрация: 16.07.2013
Сообщения: 18
Версия Delphi: Delphi XE4
Репутация: 10
По умолчанию

спасибо, буду читать
Ответить с цитированием
  #11  
Старый 21.10.2013, 16:49
Sibay Sibay вне форума
Прохожий
 
Регистрация: 21.10.2013
Сообщения: 5
Версия Delphi: Delphi XE5
Репутация: 10
По умолчанию

Перечитал свое сообщение, немного неправильно сформулировано. "Так вызывать нельзя" относилось к предыдущему сообщению, а вызывать функцию из dll разумеется можно
Ответить с цитированием
  #12  
Старый 22.10.2013, 09:41
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

>Так вызывать нельзя - метод должен быть описан внутри класса потока.
Ну не совсем так.
В Synchronize можно подать метод любого объекта, но обязательно метод и обязательно без параметров.
Ответить с цитированием
  #13  
Старый 22.10.2013, 09:49
Аватар для 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,505
Версия Delphi: XE10
Репутация: выкл
По умолчанию

Smallboy, или пользуйся тегами, или в бан, третьего не надо.
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

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