unit Main; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Generics.Collections, FMX.Controls.Presentation, FMX.StdCtrls; type TSignal = record name : string; value : Integer; isProduced : Boolean; end; TInternalQueue = TThreadedQueue; TWorker = class(TObject) strict private _queue : TInternalQueue; public constructor Create; destructor Destroy; override; procedure SetSignal(const aSignal : TSignal); function GetSignalFromQueue : TSignal; overload; function GetSignalFromQueue(out aSignal : TSignal) : Boolean; overload; end; TForm1 = class(TForm) SignalProdLabel : TLabel; SignalConsLabel : TLabel; StartProducingBtn : TButton; StartConsumingBtn : TButton; procedure FormCreate(Sender : TObject); procedure FormClose(Sender : TObject; var Action : TCloseAction); procedure StartProducingBtnClick(Sender : TObject); procedure StartConsumingBtnClick(Sender : TObject); strict private _worker : TWorker; _isProduceOn : Boolean; private {Private declarations} public procedure StartProducing; procedure StartConsuming; end; var Form1 : TForm1; implementation uses System.Math; {$R *.fmx} {TProducer} constructor TWorker.Create; begin _queue := TInternalQueue.Create(1, 0, 0); end; destructor TWorker.Destroy; begin _queue.Free; inherited; end; function TWorker.GetSignalFromQueue(out aSignal : TSignal) : Boolean; begin Result := _queue.PopItem(aSignal) = wrSignaled; end; function TWorker.GetSignalFromQueue : TSignal; begin Result := _queue.PopItem; end; procedure TWorker.SetSignal(const aSignal : TSignal); begin _queue.PushItem(aSignal); end; {TForm1} procedure TForm1.FormClose(Sender : TObject; var Action : TCloseAction); begin _worker.Free; end; procedure TForm1.FormCreate(Sender : TObject); begin _isProduceOn := True; _worker := TWorker.Create; end; procedure TForm1.StartConsuming; var signal : TSignal; begin TThread.CreateAnonymousThread( procedure var res : Boolean; begin while _isProduceOn do begin res := _worker.GetSignalFromQueue(signal); TThread.Synchronize(TThread.CurrentThread, procedure begin if res then begin SignalConsLabel.Text := Format('Consumed: %s :---: %d', [signal.name, signal.value]); end; end); end; end).Start; end; procedure TForm1.StartConsumingBtnClick(Sender : TObject); begin StartConsuming; end; procedure TForm1.StartProducingBtnClick(Sender : TObject); begin StartProducing; end; procedure TForm1.StartProducing; var signal : TSignal; begin TThread.CreateAnonymousThread( procedure begin while _isProduceOn do begin sleep(1000); signal.isProduced := True; signal.name := Format('Signal #%d', [Random(1000)]); signal.value := Random(100000); _worker.SetSignal(signal); TThread.Synchronize(TThread.CurrentThread, procedure begin SignalProdLabel.Text := Format('Produced: %s :---: %d', [signal.name, signal.value]); end); end; end).Start; end; end.