Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4   вперед  Ctrl      все
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
makhaon
Закусывать надо
Кстати, "реактивное программирование" - интересный термин. Новый наверно, раньше не встречал.
12 май 18, 13:48    [21404906]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 23697
YuRock
makhaon
Закусывать надо
Кстати, "реактивное программирование" - интересный термин. Новый наверно, раньше не встречал.

Это, наверное, как экстремальное программирование, когда мысль прет
+
и хочется в туалет.
12 май 18, 13:52    [21404914]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
Миксионисюни
Guest
stanilar
А меня учили что в Дельфи для модульности используются Unit'ы.


Простой пример
Result  := UnitName.FunctionName();


В идеале он сам должен подхватит ближайшую объявленную функцию
12 май 18, 14:19    [21404932]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
wadman
Это, наверное, как экстремальное программирование, когда мысль прет


А почему не: "А зачем это в дельфистам"?


YuRock
Кстати, "реактивное программирование" - интересный термин. Новый наверно, раньше не встречал.

Чуть постарше Дельфи. Наверное.
12 май 18, 19:57    [21405464]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
Миксионисюни
Простой пример


Пример чего? Что для разделения нужны юниты?
12 май 18, 20:00    [21405471]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
stanilar
YuRock
Кстати, "реактивное программирование" - интересный термин. Новый наверно, раньше не встречал.

Чуть постарше Дельфи. Наверное
Погуглил. Да, есть такое.
Нет, не старше, но это не важно.
Важно то, что в "реактивном программировании" речь идет о потоках данных.
А в этом топике - о потоках кода.
Это, как бы, разные сущности.
12 май 18, 20:10    [21405477]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
YuRock
А в этом топике - о потоках кода.


Автору нужно получить событие о завершении работы расчетного потока. Как раз событие завершение работы расчетного потока и есть поток данных. По сути реактивность это те-же потоки.

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

Удобно именно с точки зрения оформления кода. Конечно, можно посмотреть есть ли что в OTL, но дельфя у меня уже давно не стоит.
12 май 18, 20:39    [21405506]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
stanilar,

Всё, что ты написал, делается элементарно и на делфи и на чем угодно. Тупо вызвать коллбэки (извини, "события") у подписанных "читателей".

Только это ад несусветный. Да, иногда - удобно. Как в экселе - одна ячейка другие обновляет. Но в общем - нет.

Автору нужно не это, не огород "событий" городить. Ему нужно просто организовать очередь и в других потоках дожидаться выполнения заданий, добавленных в эту очередь.
12 май 18, 20:53    [21405522]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
YuRock
делается элементарно ...

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

YuRock
огород

Вот как раз колхозить огород тут предлагаешь именно ты. Мое предложение (будь такая возможность) - воспользоваться проработанной теорией (а если говорить про другие ЯП то и практикой).
12 май 18, 21:12    [21405554]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
stanilar
YuRock
делается элементарно ...

В сферическом примере - да. На практике будут разные ситуации типа преждевременного завершения ожидающего потока
Ну это если сделать "две функции", как предлагаешь ты. А если мониторить отписку читателей - проблемы такой не будет.
Все, конечно, больше и больше усложняется. Именно это наверно и нужно автору - усложнить задачу. Получается, так.
12 май 18, 21:38    [21405601]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
stanilar
Вот как раз колхозить огород тут предлагаешь именно ты. Мое предложение (будь такая возможность) - воспользоваться проработанной теорией (а если говорить про другие ЯП то и практикой).
Мой колхозный огород - прост, понятен и нагляден как 3 копейки.
В отличие от "теории".
12 май 18, 21:39    [21405604]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
YuRock
Мой колхозный огород - прост, понятен и нагляден как 3 копейки.


А еще он ничем не отличается от моего. В очередь ведь будут добавляться что-то типа колбэков(событий)?
12 май 18, 21:44    [21405612]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
YuRock
А если мониторить отписку читателей - проблемы такой не будет.


В реактивности, аналогично, можно отписаться от сервера событий. Речь то, на самом деле, про наличие проработанных компонент.
12 май 18, 21:48    [21405620]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
stanilar
YuRock
Мой колхозный огород - прост, понятен и нагляден как 3 копейки.


А еще он ничем не отличается от моего. В очередь ведь будут добавляться что-то типа колбэков(событий)?
Нет, конечно. Просто указатель на память под результат (если нужно).
12 май 18, 21:59    [21405634]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
YuRock
Нет, конечно.

А как сообщить ждущему потоку, что данные пришли? Он будет сам, в цикле, проверять наличие данных?
12 май 18, 22:14    [21405670]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
истопник в кедах
Guest
stanilar,
+
program LiTh;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  PJob = ^TJob;
  TJob = class
    private
      fRef    :Integer;
      fCount  :Integer;
      fData   :Pointer;
      fResult :Pointer;
      eOk     :Pointer;
      eWait   :Pointer;
      eRef    :Pointer;
      class procedure Signal(aEvent: Pointer); static; inline;
      class procedure Wait(aEvent: Pointer); static; inline;
    public
      constructor Create;
      destructor  Destroy; override;
      function  IncRef:Integer;
      procedure DecRef;
      function  Send(aData :Pointer):Pointer;
      function  Next(var aData :Pointer; var aResult :PPointer):Boolean;
  end;

constructor TJob.Create;
begin
  eOk := System.MonitorSupport.NewWaitObject();
  eRef := System.MonitorSupport.NewWaitObject();
  eWait := System.MonitorSupport.NewWaitObject();
end;

destructor TJob.Destroy;
begin
  while True do begin
    Wait(eRef);
    if fRef = 1 then Send(nil)
      else if fRef = 0 then Break;
  end;
  System.MonitorSupport.FreeWaitObject(eWait);
  System.MonitorSupport.FreeWaitObject(eRef);
  System.MonitorSupport.FreeWaitObject(eOk);
  inherited;
end;

class procedure TJob.Wait(aEvent: Pointer);
begin
  System.MonitorSupport.WaitOrSignalObject(nil, aEvent, INFINITE);
end;

class procedure TJob.Signal(aEvent: Pointer);
begin
  System.MonitorSupport.WaitOrSignalObject(aEvent, nil, 0);
end;


function TJob.IncRef:Integer;
begin
 Result := AtomicIncrement(fRef);
end;

procedure TJob.DecRef;
begin
  AtomicDecrement(fRef);
  Signal(eRef);
end;

function TJob.Send(aData: Pointer): Pointer;
begin
  System.TMonitor.Enter(Self);        // становимся в очередь
  fData := aData;                     // данные задания
  Signal(eWait);                      // сигнал о задании
  if Assigned(aData) then begin
    Wait(eOk);                        // ожидание выполнения
    Result := fResult;                // забераем результат
WriteLn(IntToStr(NativeInt(Result))); // Debug
  end;
  System.TMonitor.Exit(Self);         // уходим из очереди
end;

function TJob.Next(var aData: Pointer; var aResult: PPointer):Boolean;
begin
  if fCount>0 then Signal(eOk);       // сигнал о выполнении
  Wait(eWait);                        // ожидание задания
  aData := fData;                     // какие данные
  aResult := @fResult;                // куда результат
  Result := Assigned(aData);
  Inc(fCount);
end;

function BeginThread(ThreadFunc: TThreadFunc; Parameter: Pointer): NativeInt;
{$IFDEF POSIX}
 var d : NativeUInt; begin Result := System.BeginThread(nil, ThreadFunc, Parameter, d); end;
{$ENDIF POSIX}
{$IFDEF MSWINDOWS}
 var d : Cardinal;  begin Result := System.BeginThread(nil, 0, ThreadFunc, Parameter, 0, d); end;
{$ENDIF MSWINDOWS}


procedure Thread1(Job:TJob);
var
 aData   : Pointer;
 aResult : PPointer;
begin
 Job.IncRef;
   while Job.Next(aData, aResult)     // данные поступили
     do aResult^ := PByte(aData)+1;   // работаем
 Job.DecRef;
end;

procedure Thread234(Job:TJob);
var
 i      : Integer;
 Data   : Pointer;
 Result : Pointer;
begin
 i := Job.IncRef * 100;
   for i := i to i+3 do begin
     Data := Pointer(i);
     Result := Job.Send(Data);        // делегируем
     Sleep(Random(100));
   end;
 Job.DecRef;
end;
                                      // // // // // // //
var
  i:Integer;
  Job : TJob;
begin
  Job := TJob.Create;
    BeginThread(@Thread1, Job);
    for i := 2 to 4 do BeginThread(@Thread234, Job);
  Job.Free;
  Writeln('Fin');
end.
13 май 18, 00:57    [21405953]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
stanilar
YuRock
Нет, конечно.

А как сообщить ждущему потоку, что данные пришли? Он будет сам, в цикле, проверять наличие данных?
Взвести событие, сигнализирующее об этом.
Не коллбэк, а событие, которого ожидающий поток ждет и спит при этом, без всяких циклов.
13 май 18, 11:11    [21406126]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
Thread
Guest
YuRock
stanilar
пропущено...

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


Вот сейчас как раз сижу, разбираюсь с TEvent
Штудирую конец этой статьи: Потоки и методы их синхронизаций в Delphi
13 май 18, 14:20    [21406283]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
Thread,

Хватит TSimpleEvent. TEvent - именованные - для междупроцессных взаимодействий.
13 май 18, 14:23    [21406289]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
stanilar
Member

Откуда: Спб
Сообщений: 679
истопник в кедах

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

P/S/ Не радует меня справка любимой среды

WaitOrSignalObject help
Embarcadero Technologies does not currently have any additional information. Please help us document this topic by using the Discussion page!
13 май 18, 18:36    [21406570]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
истопник в кедах
Guest
stanilar
я это, адресатом ошибся. Пример ТС-у был - в ответ на его картинку. Ну и типа кроссплатформа.
+
 //system.pas 
  PMonitorSupport = ^TMonitorSupport;
  TMonitorSupport = record
    // Obtain a synchronization object - usually an auto-reset event or semaphore
    NewSyncObject: function: Pointer;
    // Free the synchronization object obtained from NewSyncObject
    FreeSyncObject: procedure (SyncObject: Pointer);
    // Obtain a wait object - usually an auto-reset event or semaphore - these should be cached
    NewWaitObject: function: Pointer;
    // Return the wait object from NewWaitObject back to the cache
    FreeWaitObject: procedure (WaitObject: Pointer);
    // Wait for either a SyncObject or WaitObject or signal an object
    // o WaitOrSignalObject(nil, Obj, Timeout); - Wait for <Timeout> time or until <Obj> is signaled
    // o WaitOrSignalObject(Obj, nil, 0); - Signal <Obj> and return. Timeout and WaitObject params ignored.
    WaitOrSignalObject: function (SignalObject, WaitObject: Pointer; Timeout: Cardinal): Cardinal;
  end;

Если про коллбэк - то вопрос в том, в контексте какого потока он будет выполнен и как это реализовать.
13 май 18, 19:29    [21406628]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
Thread
Guest
Я еще во многом не разобрался, но вот в процессе поиска попалась мне очень настораживающая статья: WaitForSingleObject. Why you should never use it.. Там как раз обыгрывается моя ситуация с COM объектами в потоке и как следствие скрытые окна и возможные блокировки. Но я еще не всё осознал.
13 май 18, 19:44    [21406638]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 3347
Thread,

1. Статью не читал. Эта функция - основа всех основ.
2. Если твои COM-объекты окна любят выбрасывать - то, конечно, в доп. потоке реализовать работу будет сложно, мягко говоря.
13 май 18, 20:25    [21406653]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
истопник в кедах
Guest
Thread
настораживающая статья: WaitForSingleObject. Why you should never use it..
а ещё https://www.transl-gunsmoker.ru/2010/03/msgwaitformultipleobjects.html и тогда
while true do 'Think carefully about whether a thread is the right solution to the problem';
13 май 18, 20:29    [21406654]     Ответить | Цитировать Сообщить модератору
 Re: Как организовать ожидание пока Thread не отработает задание  [new]
Thread
Guest
Спасибо всем, кто откликнулся!

Я решил (как мне кажется) проблему через два TEvent'a. Ниже выкладываю код диаграмму работы.
Бросьте пожалуйста взгляд, всё ли в порядке.


+ TThread1 = class(TThread)

type
   TThread1 = class(TThread)
   private
      FBusy                         : boolean;

      FRequest                      : string;
      FAnswer                       : string;

      FWaitRequestEvent             : TEvent;
      FOnRequestProcessedEvent      : TEvent;
   public
      procedure  AfterConstruction(); override;
      destructor Destroy(); override;
      procedure Execute(); override;

      procedure SyncExecute(const ARequest: string; var AAnswer: string);
   public
      property Busy: boolean read FBusy;
   end;


procedure TThread1.AfterConstruction();
begin
   inherited;

   FWaitRequestEvent:=TEvent.Create(nil, True, False, CreateGUID());

   FBusy := false;
end;


destructor TThread1.Destroy();
begin
   FWaitRequestEvent.Free();
   
   inherited;
end;


procedure TThread1.SyncExecute(const ARequest: string; var AAnswer: string);
var
   RequestProcessedEvent   : TEvent;
   WaitResult              : TWaitResult;
begin
   FRequest:=ARequest;
   FAnswer:='';

   FWaitRequestEvent.ResetEvent();

   RequestProcessedEvent := TEvent.Create(nil, True, False, CreateGUID());
   try
      FOnRequestProcessedEvent:=RequestProcessedEvent;
      FWaitRequestEvent.SetEvent();

      WaitResult := FOnRequestProcessedEvent.WaitFor(INFINITE);
   finally
      FOnRequestProcessedEvent := nil;
      FreeAndNil(RequestProcessedEvent);
   end;

   AAnswer:= FAnswer;
end;


procedure ___ProcessMessages();
var
   lpMsg    : TMsg;
begin
   while PeekMessage(lpMsg,0,0,0,PM_REMOVE) do
   begin
      TranslateMessage(lpMsg);
      DispatchMessage(lpMsg);
   end;
end;


procedure TThread1.Execute();
var
   ComObjects              : TMyComObjects;
   WaitResult              : TWaitResult;
begin
   CoInitialize(nil);
   try
      ComObjects := TMyComObjects.Create();
      try
         while not Terminated do
         begin
            WaitResult := FWaitRequestEvent.WaitFor(50); //50ms is not too long

            if WaitResult = wrSignaled then
            begin
               FBusy:=true;
               try
                  FWaitRequestEvent.ResetEvent();

                  Sleep(50); //50ms for preparing of FOnRequestProcessedEvent

                  try
                     ComObjects.XYZ(FRequest, FAnswer);
                  
			finally
                     FBusy:=false;
                  end;

                  if Assigned(FOnRequestProcessedEvent) then
                  begin
                     FOnRequestProcessedEvent.SetEvent();
                     FOnRequestProcessedEvent:=nil;
                  end;
               finally
                  FBusy:=false;
               end;
            end;
         end;
      finally
         if Assigned(FOnRequestProcessedEvent) then
         begin
            FOnRequestProcessedEvent.SetEvent();
            FOnRequestProcessedEvent:=nil;
         end;

         FreeAndNil(ComObjects);
         ___ProcessMessages(); // без этого вылетает Access Violation при уничтожении thread'a
      end;
   finally
      CoUnInitialize();
   end;
end;



К сообщению приложен файл. Размер - 43Kb
14 май 18, 15:12    [21408477]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4   вперед  Ctrl      все
Все форумы / Delphi Ответить