Поток Delphi, который ожидает данных, обрабатывает их, затем продолжает ожидать

<ul style="color: red;">
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
  • Один
  • Два
  • Три
  • 9
    задан Marek Jedliński 14 November 2009 в 20:52
    поделиться

    4 ответа

    OmniThreadLibrary определенно может помочь ты здесь. Тест 5 из дистрибутива OTL должен помочь вам начать.

    В этой демонстрации кнопка «Пуск» создает поток и устанавливает некоторые параметры и таймер (которые вы можете удалить в своем коде, если они не нужны). «Изменить сообщение» отправляет сообщение в поток, и это сообщение обрабатывается в методе потока OMChangeMessage. Затем поток отправляет некоторую информацию обратно клиенту (OMSendMessage в этой демонстрации, но вы можете сделать это в том же сообщении, в котором будете выполнять свою работу), и основной поток получает это сообщение через компонент OmniEventMonitor. Кнопка «Стоп» останавливает рабочий поток.

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

    РЕДАКТИРОВАТЬ

    В Delphi 2009 и более поздних версий шаблон Background Worker обеспечивает более простое решение.

    13
    ответ дан 4 December 2019 в 12:19
    поделиться

    WaitForSingleObject () может ожидать нескольких типов объектов синхронизации. Вы можете использовать объект синхронизации «событие» Windows (который не имеет ничего общего с событием Delphi). Вы создаете событие (в SyncObjs, IIRC есть оболочка Delphi TEvent) и вызываете WaitForSingleObject, чтобы дождаться передачи этого события. Когда вам нужно разбудить поток, вы вызываете SetEvent, чтобы перевести событие в сигнальное состояние, и WaitForSingleObject возвращается. Вы можете заставить поток ждать одного (или всех) из нескольких объектов с помощью функции WaitForMultipleObjects () - она ​​также сообщит вам, какой объект стал сигнализируемым.

    2
    ответ дан 4 December 2019 в 12:19
    поделиться

    Вы определенно можете отправлять сообщения в поток, даже если он не имеет дескриптора окна. Просто используйте PostThreadMessage () вместо SendMessage () или PostMessage () . Здесь, на StackOverflow, будет дополнительная информация, если вы выполните поиск PostThreadMessage () в теге [delphi] - я не думаю, что дублировать все здесь - хорошая идея.

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

    1
    ответ дан 4 December 2019 в 12:19
    поделиться

    Вот простой пример того, как это можно сделать ...

    const
      WM_MY_RESULT = WM_USER + $1;
    
    type
      TMyThread = class(TThread)
      private
        FKilled: Boolean;
        FListLock: TRTLCriticalSection;
        FList: TList;
        FJobAdded: TEvent;
      protected
        procedure Execute; override;
        procedure DoJob(AJob: Integer);
      public
        constructor Create(CreateSuspended: Boolean);
        destructor Destroy; override;
        procedure Kill;
        procedure PushJob(AJob: Integer);
        function  JobCount: Integer;
        function  GetJob: Integer;
      end;
    
    
      TThreadingForm = class(TForm)
        lstResults: TListBox;
        se: TSpinEdit;
        btn: TButton;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure btnClick(Sender: TObject);
      private
        FThread: TMyThread;
        procedure OnMyResultMessage(var Msg: TMessage); message WM_MY_RESULT;
      public
        { Public declarations }
      end;
    
    var
      ThreadingForm: TThreadingForm;
    
    implementation
    
    {$R *.dfm}
    
    { TMyThread }
    
    constructor TMyThread.Create(CreateSuspended: Boolean);
    begin
      FKilled := False;
      InitializeCriticalSection(FListLock);
      FList := TList.Create;
      FJobAdded := TEvent.Create(nil, True, False, 'job.added');
      inherited;
    end;
    
    destructor TMyThread.Destroy;
    begin
      FList.Free;
      FJobAdded.Free;
      DeleteCriticalSection(FListLock);
      inherited;
    end;
    
    procedure TMyThread.DoJob(AJob: Integer);
    var
      res: Integer;
    begin
      res := AJob * AJob * AJob * AJob * AJob * AJob;
      Sleep(1000); // so it would take some time
      PostMessage(ThreadingForm.Handle, WM_MY_RESULT, res, 0);
    end;
    
    procedure TMyThread.Execute;
    begin
      inherited;
      while not FKilled or not Self.Terminated do
      begin
        EnterCriticalSection(FListLock);
        if JobCount > 0 then
        begin
          LeaveCriticalSection(FListLock);
          DoJob(GetJob)
        end
        else
        begin
          FJobAdded.ResetEvent;
          LeaveCriticalSection(FListLock);
          FJobAdded.WaitFor(10000);
        end;
      end;
    end;
    
    function TMyThread.GetJob: Integer;
    begin
      EnterCriticalSection(FListLock);
      try
        Result := Integer(FList[0]);
        FList.Delete(0);
      finally
        LeaveCriticalSection(FListLock);
      end;
    end;
    
    function TMyThread.JobCount: Integer;
    begin
      EnterCriticalSection(FListLock);
      Result := FList.Count;
      LeaveCriticalSection(FListLock);
    end;
    
    procedure TMyThread.Kill;
    begin
      FKilled := True;
      FJobAdded.SetEvent;
      Terminate;
    end;
    
    procedure TMyThread.PushJob(AJob: Integer);
    begin
      EnterCriticalSection(FListLock);
      try
        FList.Add(Pointer(AJob));
        FJobAdded.SetEvent;
      finally
        LeaveCriticalSection(FListLock);
      end;
    end;
    
    { TThreadingForm }
    
    procedure TThreadingForm.OnMyResultMessage(var Msg: TMessage);
    begin
      lstResults.Items.Add(IntToStr(Msg.WParam));
    end;
    
    procedure TThreadingForm.FormCreate(Sender: TObject);
    begin
      FThread := TMyThread.Create(False);
    end;
    
    procedure TThreadingForm.FormDestroy(Sender: TObject);
    begin
      FThread.Kill;
      FThread.WaitFor;
      FThread.Free;
    end;
    
    procedure TThreadingForm.btnClick(Sender: TObject);
    begin
      FThread.PushJob(se.Value);
    end;
    
    1
    ответ дан 4 December 2019 в 12:19
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: