Перейти к содержанию
Fire Monkey от А до Я
  • 0

обновление визуальных компонентов


gonzales

Вопрос

Доброго времени суток!

Интересует вопрос, больше по технологии, чем конкретной реализации. 

Задача такая, на форме есть много компонентов (это динамический массив, условно при разных условиях отображаются разные компоненты), отображающих информацию, хранящуюся на сервере. Соответственно для отображения изменений есть таймер, который раз в секунду кидает на сервер запрос, для каких компонентов нужна информация. Получая и распарсивая ответ меняю информацию на визуальных контролах. Нет ли технологии, чтобы сервер сам отдавал мне информацию, когда у него изменяется тот или иной компонент? И еще примечание, клиентов у сервера может быть несколько, на всех естественно должна отображаться актуальная информация.

 

Заранее спасибо, буду благодарен за любые идеи

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
2 часа назад, IVGSoft сказал:

Синхронизация нужна при обращении к визуальным компонентам. И то только при обновлении (перерисовке) их свойств. Для чтения не надо.

Да, именно так. Если есть изменения визуальных компонентов - надо использовать синхронизацию.

Вот тут лучше перестраховаться и взять за правило принцип "Любое обращение к адресному пространству другого потока выполнять потокобезопасными способами". Потому как даже чтение может привести к непредсказуемым результатам - читаете вы данные, строку к примеру из другого потока, прочитали половину, а тот поток в это время перезаписал содержимое ячеек памяти, и вы после этого читаете оставшуюся половину. Вместо ожидаемых данных получаете черте что. Это грубый пример конечно.

Ссылка на комментарий
  • 0
18 минут назад, Евгений Корепов сказал:

Вот тут лучше перестраховаться и взять за правило принцип "Любое обращение к адресному пространству другого потока выполнять потокобезопасными способами". Потому как даже чтение может привести к непредсказуемым результатам - читаете вы данные, строку к примеру из другого потока, прочитали половину, а тот поток в это время перезаписал содержимое ячеек памяти, и вы после этого читаете оставшуюся половину. Вместо ожидаемых данных получаете черте что. Это грубый пример конечно.

В общем, согласен. На практике же пока не стыкался с такими проблемами. Такое может случиться в каком-то интенсивном приложении, согласен.

Потокобезопасность превыше всего. :) Но зачастую это выглядит как в анекдоте про монашку, свечу и презерватив.

Ссылка на комментарий
  • 0
12 минут назад, Евгений Корепов сказал:

Вот тут лучше перестраховаться и взять за правило принцип "Любое обращение к адресному пространству другого потока выполнять потокобезопасными способами". Потому как даже чтение может привести к непредсказуемым результатам - читаете вы данные, строку к примеру из другого потока, прочитали половину, а тот поток в это время перезаписал содержимое ячеек памяти, и вы после этого читаете оставшуюся половину. Вместо ожидаемых данных получаете черте что. Это грубый пример конечно.

вот поэтому я и спрашивал.

Созрел еще вопрос, ситуация такая, в главном потоке идет запрос на сервер и должна быть обработка ответа, которая приводит к определенным действиям, опять же в главном потоке. Но так как я вынес ответ сервера в поток, то в главном потоке я не вижу реакции. То есть было вот так

  FillHTTPRequest(0, 0, HTTP_GET_DEVICE_COUNT);
  if AnswerIsComming = HTTP_GET_DEVICE_COUNT then
  begin
    DeviceCount := HTTPAnswer.Data1;
  end;

я делал запрос (FillHTTPRequest), и выдавал ответ (HTTPAnswer), а теперь у меня HTTPAnswer появляется в отдельном потоке. Могу ли я принудительно вызвать обработку потока Execute.

То есть примерно вот так

  FillHTTPRequest(0, 0, HTTP_GET_DEVICE_COUNT);
  Thread.Execute;
  if AnswerIsComming = HTTP_GET_DEVICE_COUNT then
  begin
    DeviceCount := HTTPAnswer.Data1;
  end;

Но метод Execute - приватный, я могу сделать дополнительный метод для обработки данных на клиенте и просто запускать его в Execute, или это не безопасно? 

Ссылка на комментарий
  • 0
2 минуты назад, gonzales сказал:

метод Execute

Вы не можете его вызывать. Да и не надо.

Передавайте потоку сигналы для управления. И отслеживайте их в методе Execute. И наоборот - пришел ответ от сервера в потоке - сигнализируйте главному потоку о получении.

Ссылка на комментарий
  • 0
5 минут назад, IVGSoft сказал:

И наоборот - пришел ответ от сервера в потоке - сигнализируйте главному потоку о получении.

Так вот в этом как раз и вопрос, как мне заставить главный поток ждать ответа от сервера, если ответ приходит не в главном потоке?

Ссылка на комментарий
  • 0
3 минуты назад, gonzales сказал:

Так вот в этом как раз и вопрос, как мне заставить главный поток ждать ответа от сервера, если ответ приходит не в главном потоке?

А хоспади! :) Заведите свойство у потока скажем property IsAnswerReceived : boolean read fIsAnswerReceived;

В начале цикла в методе Execute сбрасывайте его на false, а по приходу ответа выставляйте в  true.

В главном же потоке проверяйте это свойство. Так узнаете есть ответ или нету.

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

Сам обработчик пишете в главном потоке и присваиваете его слушающему потоку при (после) создании.

Ссылка на комментарий
  • 0

Вот пример (обрезанный) из другого проекта :

TJobCompleteEvent = procedure(Sender: TObject; Success: boolean) of object;
  TivgImageProcessor = class(TThread)
  private
	...

    fOnGrayScaleReady: TImageProcessedEvent;
    fOnEdgeMapReady: TImageProcessedEvent;
    fOnUnfilteredLinesReady: TImageProcessedEvent;
    fOnFilteredLinesReady: TImageProcessedEvent;
    fOnHaughSpaceImageReady: TImageProcessedEvent;
    fOnScreenImageReady: TImageProcessedEvent;
    fOnFullSizeReady: TImageProcessedEvent;
    fOnPreviewReady: TImageProcessedEvent;
    fOnResultReady: TResultReadyEvent;
    fOnCurveReady: TResultReadyEvent;
    fOnError: TProcessingErrorEvent;
    fOnNotify: TProcessingNotifyEvent;
    fOnJobComplete: TJobCompleteEvent;

    procedure DoULinesReady;
    procedure DoFLinesReady;
    procedure DoHaughSpaceReady;
    procedure DoGrayImgReady;
    procedure DoEdgeMapReady;
    procedure DoResultReady;
    procedure DoScreenReady;
    procedure DoFullSizeImgReady;
    procedure DoPreviewReady;
    procedure DoCurveReady;
    procedure DoError;
    procedure DoNotify;
    procedure DoJobComplete;

    procedure DoLoad(var aTask: TProcessingTask);
    procedure DoSave(aTask: TProcessingTask);
    procedure DoCropCalculate(aSrc: TBitmapSurface; out res: TProcessingResult);
    procedure DoCrop;
    procedure DoRotate;
    procedure DoAdjust;
    procedure DoPreview;
    procedure DoCannyTrace(bm_in, bm_out: TBitmapSurface; lowerThreshold, upperThreshold: integer);
    procedure Convolve(ABitmap: TBitmapSurface; AMask: T3x3FloatArray; ABias: integer);

  protected
    procedure Execute; override;
    function ExecuteTask(aTask: TProcessingTask): boolean; virtual;

  public
    constructor Create(aVer : string);
    destructor Destroy; override;

    procedure AbortBatch;

    procedure RunBatch(Jobs: TProcessingJobs; inputImages: TStringDynArray;
      CanOverwrite: boolean; outPath, outExt: string;
      multPage: boolean; mirroring : integer = 0); overload;
    procedure RunBatch(Jobs: TProcessingJobs; FromPath, ToPath: string;
      outExt: string; CanOverwrite: boolean; multPage: boolean; mirroring : integer = 0); overload;
    procedure RunSingleTask(aTask: TProcessingTask);
    procedure SharpenImg(aBmp: TBitmapSurface; aVal: single);
    procedure CalcImgCropRect(SourceImg: TBitmapSurface);
    procedure MakePreview(aMirror : integer);

    // color correction
    procedure DoColorCorrection(aSrc: TBitmapSurface); overload;
    procedure DoColorCorrection(aSrc: TBitmapSurface; fCrv : TCorrectionCurve); overload;

    function PavlidisContourTrace(aBmp: TBitmapSurface; sx, sy: integer;
      coords: PCoordinates; const aWorkArea: TRect): TPavResult;

    // events
    property OnGrayImageReady: TImageProcessedEvent read fOnGrayScaleReady write fOnGrayScaleReady;
    property OnEdgeMapReady: TImageProcessedEvent read fOnEdgeMapReady write fOnEdgeMapReady;
    property OnUnfilteredLinesReady: TImageProcessedEvent read fOnUnfilteredLinesReady write fOnUnfilteredLinesReady;
    property OnFilteredLinesReady: TImageProcessedEvent read fOnFilteredLinesReady write fOnFilteredLinesReady;
    property OnHaughSpaceReady : TImageProcessedEvent read fOnHaughSpaceImageReady write fOnHaughSpaceImageReady;
    property OnScreenImageReady: TImageProcessedEvent read fOnScreenImageReady write fOnScreenImageReady;
    property OnFullSizeReady: TImageProcessedEvent read fOnFullSizeReady write fOnFullSizeReady;
    property OnPreviewReady: TImageProcessedEvent read fOnPreviewReady write fOnPreviewReady;
    property OnResultReady: TResultReadyEvent read fOnResultReady write fOnResultReady;
    property OnCurveReady: TResultReadyEvent read fOnCurveReady write fOnCurveReady;
    property OnError: TProcessingErrorEvent read fOnError write fOnError;
    property OnNotify: TProcessingNotifyEvent read fOnNotify write fOnNotify;
    property OnJobComplete: TJobCompleteEvent read fOnJobComplete write fOnJobComplete;
  end;

procedure TivgImageProcessor.DoJobComplete;
begin
  if Assigned(fOnJobComplete) then
    fOnJobComplete(Self, fSuccess);
end;

...

procedure TivgImageProcessor.DoHaughSpaceReady;
begin
  if Assigned(fOnHaughSpaceImageReady) then
    fOnHaughSpaceImageReady(Self, fImgToShow);
end;

...

procedure TivgImageProcessor.Execute;

begin
  while not Self.Terminated do
  begin
    if not fTaskComplete then
      try
        while (fProcTasks.Count <> 0) and not fStoped do
        begin
          fSuccess := true;
          fTaskActive := true;
          try
            try
              fCurrentTask := fProcTasks[0];
              ExecuteTask(fProcTasks[0]);
              Inc(fSuccessCounter);
            except
              on E: Exception do
              begin
                Inc(fErrorsCounter);
                fErrorMsg := E.Message;
                Synchronize(DoError);
              end;
            end;
          finally
            fProcTasks.Delete(0);
            Inc(fJobsFinished);
            fTaskActive := false;
          end;
        end;
        if fCurrentTask.MultiPaged and not fStoped then
        begin
          if fUseCompression then
            fNotification := 'Saving multipage PDF document. Estimated time - '
              + FormatDateTime('hh:nn:ss',
              SecondsToDateTime(cPDFPAGESAVINGTIME * fJobsTotal))
          else
            fNotification := 'Saving multipage PDF document. Estimated time - '
              + FormatDateTime('hh:nn:ss',
              SecondsToDateTime(uPDFPAGESAVINGTIME * fJobsTotal));
          Synchronize(DoNotify);
          MultiPagePDF.SaveToFile(fCurrentTask.ToPath);

        end;
        fTaskComplete := true;
        fSuccess := true;
        if fStoped then
        begin
          fNotification := 'Batch processing aborted!';
          fSuccess := false;
          fProcTasks.Clear;
        end
        else
          fNotification := 'Job complete';
        fStoped := false;
        Synchronize(DoNotify);
        Synchronize(DoJobComplete);
      except
        on E: Exception do
        begin
          Inc(fErrorsCounter);
          fTaskActive := false;
          fTaskComplete := true;
          fSuccess := false;
          fErrorMsg := 'Task processing failed! Err :: ' + E.Message;
          DoError;
          Synchronize(DoJobComplete);
        end;
      end;

    Self.Sleep(1);
  end;
end;

 

Ссылка на комментарий
  • 0

Спасибо за пример, но по ходу я нуб 80 уровня, я не вижу, чем он может мне помочь.

Посмотрите плиз конструкцию, она работает очень криво, но я не могу понять почему

Вот класс

type
  TClusterClient = class(TThread)
  public
    procedure ReadPacket(HTTPAnswer: THTTPAnswer);
    procedure ChechClient;
  protected
    procedure Execute; override;
  end;

procedure TClusterClient.ChechClient;
var
  Len: integer;
  Buf: TIdBytes;
  H: THTTPAnswer;
begin
  if form1.Client1.Socket.InputBufferIsEmpty = false then
  begin
    try
      SetLength(Buf, SizeOf(THTTPAnswer));
      form1.Client1.Socket.ReadBytes(Buf, SizeOf(THTTPAnswer), false);
      Move(Buf[0], H, Length(Buf));
      ReadPacket(H);
    finally
      SetLength(Buf, 0);
    end;
  end;
end;

procedure TClusterClient.Execute;
begin
  while not Terminated do
  begin
    try
      if form1.Client1.Connected then
      begin
        if form1.Client1.Socket.CheckForDataOnSource(100) then
        begin
         ChechClient;
        end;
      end;
    except

    end;
  end;
end;

procedure TClusterClient.ReadPacket(HTTPAnswer: THTTPAnswer);
var
  t_out, t_in: TIdBytes;
  Size: TSizeF;
  i, j: integer;
  l: integer;
  // d, a: byte;
  VirtualNode: IXMLNode;
  VirtualElementNode: IXMLNode;
  c: cardinal;
  s: string;
begin
  if (HTTPAnswer.Preamble[0] = 67) and (HTTPAnswer.Preamble[1] = 76) and (HTTPAnswer.Preamble[2] = 85) then
  begin
    TThread.Synchronize(nil,
      procedure
      begin
        form1.AnswerIsComming := HTTPAnswer.Command;
        form1.HTTPAnswer := HTTPAnswer;
      end);
  end

  else if (HTTPAnswer.Preamble[0] = 85) and (HTTPAnswer.Preamble[1] = 80) and (HTTPAnswer.Preamble[2] = 68) then
  begin
    if HTTPAnswer.Command = HTTP_SEND_ELEMENT_UPDATE then
    begin
      for i := 0 to Length(form1.RoomElements) - 1 do
      begin
        if HTTPAnswer.Data10 = 1 then // устройства
        begin
          if (form1.RoomElements[i] is TRele) { and (MasterTask.Status <> TTaskStatus.Canceled) } then
          begin
            TThread.Synchronize(nil,
              procedure
              var
                d, a: byte;
              begin
                d := (form1.RoomElements[i] as TRele).Device_ID;
                a := (form1.RoomElements[i] as TRele).Device_Adress;
                if (d = HTTPAnswer.Device_ID) and (a = HTTPAnswer.Device_Adress) then

                  form1.device[d].Board[a].CurrentValue := HTTPAnswer.Data2;
                (form1.RoomElements[i] as TRele).ReleSwitch.IsChecked := form1.device[d].Board[a]
                  .CurrentValue.ToBoolean;
                form1.ConnectImage.Bitmap := form1.IconList.Bitmap(Size, 15);
              end);
          end;
        end;
      end;
    end;
  end;
end;

А вот запрос информации с сервера из главного потока

procedure TForm1.SendHTTPMessage(ReadTimeout: integer);
var
  t_out, t_in: TIdBytes;
  Size: TSizeF;
begin
  TriesToSend := 0;
  if ReadTimeout = -1 then
  begin
    if LocalIP = true then
    begin
      Client1.ConnectTimeout := 500;
      Client1.ReadTimeout := 1000;
    end
    else
    begin
      Client1.ConnectTimeout := 500;
      Client1.ReadTimeout := 2000;
    end;
  end
  else
  begin
    Client1.ConnectTimeout := 1000;
    Client1.ReadTimeout := ReadTimeout;
  end;

  HTTPAnswer.Preamble[0] := 0;
  HTTPAnswer.Preamble[1] := 0;
  HTTPAnswer.Preamble[2] := 0;
  HTTPAnswer.Device_ID := 0;
  HTTPAnswer.Device_Adress := 0;
  HTTPAnswer.Command := 0;
  HTTPAnswer.Data1 := 0;
  HTTPAnswer.Data2 := 0;
  HTTPAnswer.Data3 := 0;
  HTTPAnswer.Data4 := 0;
  HTTPAnswer.Data5 := 0;
  HTTPAnswer.Data6 := 0;
  HTTPAnswer.Data7 := 0;
  HTTPAnswer.Data8 := 0;
  HTTPAnswer.Data9 := 0;
  HTTPAnswer.Data10 := 0;
  try
    Size.cx := 16;
    Size.cy := 16;
    if Client1.Connected = false then
      Client1.Connect;

    if Client1.Connected = true then
    begin
      Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 15);
      AnswerIsComming := 0;
      SetLength(t_out, SizeOf(HTTPRequest));
      Move(HTTPRequest, t_out[0], SizeOf(HTTPRequest));
      Client1.Socket.WriteBufferOpen;
      Client1.Socket.Write(t_out, SizeOf(HTTPRequest));
      Client1.Socket.WriteBufferFlush;
      Client1.Socket.WriteBufferClose;
      Client1.Socket.CheckForDataOnSource(100);
      while Client1.Socket.InputBufferIsEmpty = true do
        Client1.Socket.CheckForDataOnSource(100);
      if Client1.Socket.InputBufferIsEmpty = false then
      begin
        while HTTPRequest.Command <> Form1.AnswerIsComming do
        begin
          Client1.Socket.CheckForDataOnSource(100);
          TriesToSend := TriesToSend + 1;
          if TriesToSend < 10 then
          begin
            ClusterClient.ChechClient;
          end
          else
          begin
            Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 7);
            AnswerIsComming := 0;
            break;
          end;
        end;
      end;
    end
    else
    begin
      Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 7);
      AnswerIsComming := 0;
    end;
  except
    on E: Exception do
    begin
      AnswerIsComming := 0;
      Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 7);
    end;
  end;

end;

Суть в том, что после передачи на сервер команды я жду появления Form1.AnswerIsComming той команды, которую я послал. Пока ее нет, обращаюсь ClusterClient.ChechClient;

Работает как-то не стабильно, то получаю ответ, то нет

Ссылка на комментарий
  • 0

Я же писал - заведите флажок у слушающего потока. И его дергайте в Екзекьют. А в основном цикле проверяйте состояние его.

И тогда уберите  вот єти строки :

      Client1.Socket.CheckForDataOnSource(100);
      while Client1.Socket.InputBufferIsEmpty = true do
        Client1.Socket.CheckForDataOnSource(100);

И вообще меняйте архитектуру :)

Отправили запрос - закончили процедуру. Поток ждет прихода ответа. Пришел ответ - или вызываем какой-то метод обработки или сигнализируем главному потоку об ответе. Все. Иначе будет глюк на глюке и глюком погонять. И никакой асинхронности.

Ссылка на комментарий
  • 0
7 минут назад, IVGSoft сказал:

Я же писал - заведите флажок у слушающего потока.

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

12 минут назад, IVGSoft сказал:

И вообще меняйте архитектуру :)

Отправили запрос - закончили процедуру. Поток ждет прихода ответа. Пришел ответ - или вызываем какой-то метод обработки или сигнализируем главному потоку об ответе. Все. Иначе будет глюк на глюке и глюком погонять. И никакой асинхронности.

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

Ссылка на комментарий
  • 0
13 часов назад, IVGSoft сказал:

Снабдите запрос уникальным идентификатором. 

Есть у меня такой. Проблема не в идентификации ответа, а в очередности прихода сообщений, как выполнить следующий запрос на основании ответа от предыдущего, если я не знаю, когда его (ответ) получу, и какой он будет в очереди.

Ссылка на комментарий
  • 0
1 час назад, gonzales сказал:

Есть у меня такой. Проблема не в идентификации ответа, а в очередности прихода сообщений, как выполнить следующий запрос на основании ответа от предыдущего, если я не знаю, когда его (ответ) получу, и какой он будет в очереди.

А опишите вашу концепцию движения данных. Что вообще за комплекс приложений, какие команды, какие ответы? Мы, посредством мозгового штурма, дадим вам варианты решений.

Ссылка на комментарий
  • 0

Спасибо за поддержку!

Суть в следующем,

есть сервер (самописный TCP), крутится на микроконтроллере, есть клиенты (в основном Android, iOS). К серверу подключен ряд устройств. Клиенты управляют сервером посредством управляющих команд (конфигурируют устройства, настраивают логику работы и т.д), и получают ответы об изменениях в устройствах. Был разработан некий универсальный протокол общения (id адресата, id отправителя, id команды, параметры) в 15 байт. То есть клиент посылает пакет в 15 байт, и сервер отвечает пакетом в 15 байт. На текущий момент есть около 100 команд для общения. Например для конфигурирования устройства я посылаю команду с указанием типа устройства, после получения положительного ответа, посылаю команду с уставкой, после получения ответа посылаю команду на старт, и так далее. Также сервер рассылает информацию клиентам об изменениях в устройствах. В общем все работает в одном потоке, но если какое-то из устройств не ответит вовремя, то возникает задержка, из-за чего хочется запихнуть все общение на клиенте в поток. 

Надеюсь понятно расписал, но мог что-то уточнить.  

Ссылка на комментарий
  • 0
13 минут назад, gonzales сказал:

Спасибо за поддержку!

Суть в следующем,

есть сервер (самописный TCP), крутится на микроконтроллере, есть клиенты (в основном Android, iOS). К серверу подключен ряд устройств. Клиенты управляют сервером посредством управляющих команд (конфигурируют устройства, настраивают логику работы и т.д), и получают ответы об изменениях в устройствах. Был разработан некий универсальный протокол общения (id адресата, id отправителя, id команды, параметры) в 15 байт. То есть клиент посылает пакет в 15 байт, и сервер отвечает пакетом в 15 байт. На текущий момент есть около 100 команд для общения. Например для конфигурирования устройства я посылаю команду с указанием типа устройства, после получения положительного ответа, посылаю команду с уставкой, после получения ответа посылаю команду на старт, и так далее. Также сервер рассылает информацию клиентам об изменениях в устройствах. В общем все работает в одном потоке, но если какое-то из устройств не ответит вовремя, то возникает задержка, из-за чего хочется запихнуть все общение на клиенте в поток. 

Надеюсь понятно расписал, но мог что-то уточнить.  

Подобные задачи я решаю обычно следующим способом:

1. Разделяю приложение на две части: интерфейс и класс обеспечивающий непосредственно работу с внешним сервером.

2. Класс обеспечивает доступ к высокоуровневым методам управления со стороны интерфейса (т.е. интерфейс должен сказать классу - включи лампочку в туалете, а класс уже обеспечивает всю низкоуровневую работу, проверку состояния, отправку последовательности команд и т.д.).  Класс можно сделать в контексте основного потока главной формы.

3. У класса должен быть потомок-поток, который обеспечивает непосредственно работу с TCP, обрабатывает полученные результаты и отдает классу-родителю ответы.

Общение между классом и потоком лучше организовать по следующей схеме:

1. Из класса в поток - потоко-безопасная очередь TThreadQueue передающая Record к примеру такого вида

TCommandRecord = Record
	CommandName : String; // или Integer
	Address : String;
	Command : TArray<Byte>;
	Parameter : TArray<Byte>;
	Error : Boolean;
	ErrorMessage : String;
	Result : TArray<Byte>; // или String
	UID : Integer;
end;

Это для примера. В реальности вам придется что то убрать, что то добавить.

2. Из потока в класс можно сделать или очередь  TThreadQueue, или Event. 

Для вашего случая, обеспечения потока команд я бы следующую систему - у класса сделать список командных очередей TList. Перед началом отсылки команд, создаем очередь команд TQueue<TCommandRecord>, заполняем очередь из некоего шаблона (первая команда тип устройсва, вторая команда установка, третья команда старт и т.д.) и отдаем эту очередь в работу. Система отправляет из очереди первую команду в поток (снабженную идентификаторм очереди), поток отправляет ее в сеть, получает ответ, заполняет TCommandRecord (сохраняя идентификатор очереди) и отдает TCommandRecord в класс. Класс, по идентификатору находит нужную очередь, проверяет отсутствие ошибок и оправляет следующую команду из этой очереди.. Когда очередь команд пуста, удаляем ее из списка очередей.

Вот как то так. 

Ссылка на комментарий
  • 0

Спасибо, идею я понял, надо мне ее осмыслить. А что делает главный поток, пока класс ждет ответа от потока?

Вот, например, инициализация устройств, я шлю команду "КОЛ-ВО_УСТРОЙСТВ", получаю ответ, допустим 5, далее цикл от 1 до 5 с командой "ОПРОС_УСТРОЙСТВА", получаю ответ "ОК", отдаю в интерфейс информацию.

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

 

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...