Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can build a thread-safe Queue class which is used in a <a href="http://en.wikipedia.org/wiki/Producer-consumer_problem" rel="nofollow">Producer-Consumer</a> model. Your TThread descendant class should own an instance of this Queue class.</p> <p>When you start your application, your queue is empty, and your logging thread is blocked waiting for queue. When you push a new string into the queue from the main thread, your queue pulses the logging thread, your logging thread wakes up and pops items from the queue until the queue is empty again.</p> <p>To implement the queue in <strong>Delphi 2010</strong>, you can use <a href="http://docwiki.embarcadero.com/VCL/en/Generics.Collections.TQueue" rel="nofollow">TQueue</a> generic class as the base type, and use <a href="http://docwiki.embarcadero.com/VCL/en/System.TMonitor" rel="nofollow">System.TMonitor</a> for synchronization. In <strong>Delphi XE</strong>, there is already a class which implements this for you, named <a href="http://docwiki.embarcadero.com/VCL/en/Generics.Collections.TThreadedQueue" rel="nofollow">TThreadedQueue</a>. So If you are using Delphi XE, create an instance of TThreadedQueue, and in your logging thread try to call its PopItem() method.</p> <p><strong>EDIT:</strong></p> <p>Here is a sample logging thread which receives string logs:</p> <pre><code>unit uLoggingThread; interface uses SysUtils, Classes, Generics.Collections, SyncObjs {$IFDEF MSWINDOWS} , Windows {$ENDIF}; type TLoggingThread = class(TThread) private FFileName : string; FLogQueue : TThreadedQueue&lt;string&gt;; protected procedure Execute; override; public constructor Create(const FileName: string); destructor Destroy; override; property LogQueue: TThreadedQueue&lt;string&gt; read FLogQueue; end; implementation { TLoggingThread } constructor TLoggingThread.Create(const FileName: string); begin inherited Create(False); FFileName := FileName; FLogQueue := TThreadedQueue&lt;string&gt;.Create; end; destructor TLoggingThread.Destroy; begin FLogQueue.Free; inherited; end; procedure TLoggingThread.Execute; var LogFile : TFileStream; FileMode : Word; ALog : string; begin NameThreadForDebugging('Logging Thread'); // FreeOnTerminate := True; if FileExists(FFileName) then FileMode := fmOpenWrite or fmShareDenyWrite else FileMode := fmCreate or fmShareDenyWrite; LogFile := TFileStream.Create(FFileName,FileMode); try while not Terminated do begin ALog := FLogQueue.PopItem; if (ALog &lt;&gt; '') then LogFile.Write(ALog[1],Length(ALog)*SizeOf(Char)); end; finally LogFile.Free; end; end; end. </code></pre> <p>This TThread descendant uses a TThreadedQueue object as a buffer. When FLogQueue.PopItem is called, if the queue is empty, the thread goes to sleep, and waits until something is pushed into the queue. When an item is available in the queue, the thread pops it, and writes it to a file. This is a very simple code to just let you understand the basics of what you should do.</p> <p>And here is a sample code for a form which is running in the context of main thread, and is logging a sample message:</p> <pre><code>unit fMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, uLogginThread; type TfrmMain = class(TForm) btnAddLog: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure btnAddLogClick(Sender: TObject); private FLoggingThread : TLoggingThread; public { Public declarations } end; var frmMain: TfrmMain; implementation {$R *.dfm} procedure TfrmMain.FormCreate(Sender: TObject); begin FLoggingThread := TLoggingThread.Create(ExtractFilePath(Application.ExeName) + 'Logs.txt'); end; procedure TfrmMain.FormDestroy(Sender: TObject); begin FLoggingThread.Terminate; FLoggingThread.LogQueue.DoShutDown; FLoggingThread.WaitFor; FreeAndNil(FLoggingThread); end; procedure TfrmMain.btnAddLogClick(Sender: TObject); begin FLoggingThread.LogQueue.PushItem('This is a test log. '); end; end. </code></pre> <p>Here an instance of TLoggingThread is created when the form is initialized. When you press btnAddLog, a sample message is sent to the logger thread via its LogQueue property. Take note of how the thread is terminated in FormDestroy method. First the thread is signaled that it is terminated, then we tell LogQueue to release any lock, so if the logger thread is waiting for the queue, it will wake up automatically after calling DoShutDown. Then we wait for the thread to finish up by calling WaitFor method, and eventually we destroy the thread instance.</p> <p>Good Luck</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload