Note that there are some explanatory texts on larger screens.

plurals
  1. POMulti-threaded application interaction with logger thread
    text
    copied!<p>Here I am again with questions about multi-threading and an exercise of my <strong>Concurrent Programming</strong> class.</p> <p>I have a multi-threaded server - implemented using .NET <em>Asynchronous Programming Model</em> - with <code>GET</code> (<em>download</em>) and <code>PUT</code> (<em>upload</em>) file services. This part is done and tested.</p> <p>It happens that the statement of the problem says this server must have <em>logging</em> activity with the minimum impact on the server response time, and it should be supported by a low priority <em>thread</em> - <em>logger thread</em> - created for this effect. All <em>logging</em> messages shall be passed by the <em>threads</em> that produce them to this <em>logger thread</em>, using a communication mechanism that <strong>may not</strong> lock the <em>thread</em> that invokes it (besides the necessary locking to ensure mutual exclusion) and assuming that some <em>logging messages</em> may be ignored.</p> <p>Here is my current solution, please help validating if this stands as a solution to the stated problem:</p> <pre><code>using System; using System.IO; using System.Threading; // Multi-threaded Logger public class Logger { // textwriter to use as logging output protected readonly TextWriter _output; // logger thread protected Thread _loggerThread; // logger thread wait timeout protected int _timeOut = 500; //500ms // amount of log requests attended protected volatile int reqNr = 0; // logging queue protected readonly object[] _queue; protected struct LogObj { public DateTime _start; public string _msg; public LogObj(string msg) { _start = DateTime.Now; _msg = msg; } public LogObj(DateTime start, string msg) { _start = start; _msg = msg; } public override string ToString() { return String.Format("{0}: {1}", _start, _msg); } } public Logger(int dimension,TextWriter output) { /// initialize queue with parameterized dimension this._queue = new object[dimension]; // initialize logging output this._output = output; // initialize logger thread Start(); } public Logger() { // initialize queue with 10 positions this._queue = new object[10]; // initialize logging output to use console output this._output = Console.Out; // initialize logger thread Start(); } public void Log(string msg) { lock (this) { for (int i = 0; i &lt; _queue.Length; i++) { // seek for the first available position on queue if (_queue[i] == null) { // insert pending log into queue position _queue[i] = new LogObj(DateTime.Now, msg); // notify logger thread for a pending log on the queue Monitor.Pulse(this); break; } // if there aren't any available positions on logging queue, this // log is not considered and the thread returns } } } public void GetLog() { lock (this) { while(true) { for (int i = 0; i &lt; _queue.Length; i++) { // seek all occupied positions on queue (those who have logs) if (_queue[i] != null) { // log LogObj obj = (LogObj)_queue[i]; // makes this position available _queue[i] = null; // print log into output stream _output.WriteLine(String.Format("[Thread #{0} | {1}ms] {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.Subtract(obj._start).TotalMilliseconds, obj.ToString())); } } // after printing all pending log's (or if there aren't any pending log's), // the thread waits until another log arrives //Monitor.Wait(this, _timeOut); Monitor.Wait(this); } } } // Starts logger thread activity public void Start() { // Create the thread object, passing in the Logger.Start method // via a ThreadStart delegate. This does not start the thread. _loggerThread = new Thread(this.GetLog); _loggerThread.Priority = ThreadPriority.Lowest; _loggerThread.Start(); } // Stops logger thread activity public void Stop() { _loggerThread.Abort(); _loggerThread = null; } // Increments number of attended log requests public void IncReq() { reqNr++; } } </code></pre> <p>Basically, here are the main points of this code:</p> <ol> <li>Start a low priority <em>thread</em> that loops the <em>logging queue</em> and prints pending <em>logs</em> to the output. After this, the <em>thread</em> is suspended till new <em>log</em> arrives;</li> <li>When a log arrives, the logger thread is awaken and does it's work.</li> </ol> <p>Is this solution <em>thread-safe</em>? I have been reading <em>Producers-Consumers</em> problem and solution algorithm, but in this problem although I have multiple producers, I only have one reader.</p> <p>Thanks in advance for all your attention.</p>
 

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