- the code has the author as a var instance, but uses a static locker. If you had multiple instances writing different files, there is no reason why they would need to use the same lock.
- in the corresponding note, since you already have a writer (as a private instance of var), you can use this to lock instead of using a separate lock object in this case - this makes things a little easier.
The “correct answer” really depends on what you are looking for in terms of blocking / blocking. For example, it’s easiest to skip the intermediate data structure, just have the WriteValues method so that each stream reports its results and writes them to a file. Something like:
StreamWriter writer = new StreamWriter("file"); public void WriteValues(IEnumerable<double> values) { lock (writer) { foreach (var d in values) { writer.WriteLine(d); } writer.Flush(); } }
Of course, this means that workflows are serialized during the “report results” phases depending on the performance characteristics, which can be just good (5 minutes to create, for example, 500 ms for recording).
At the other end of the spectrum, you must write workflows to the data structure. If you're in .NET 4, I would recommend using ConcurrentQueue instead of doing it yourself.
In addition, you can make input / output files in larger batches than those reported by worker threads, so you can just write in the background thread at some frequency. This end of the spectrum looks something like this: you have to remove the Console.WriteLine calls in real code, they are just there so you can see how it works in action)
public class ThreadSafeFileBuffer<T> : IDisposable { private readonly StreamWriter m_writer; private readonly ConcurrentQueue<T> m_buffer = new ConcurrentQueue<T>(); private readonly Timer m_timer; public ThreadSafeFileBuffer(string filePath, int flushPeriodInSeconds = 5) { m_writer = new StreamWriter(filePath); var flushPeriod = TimeSpan.FromSeconds(flushPeriodInSeconds); m_timer = new Timer(FlushBuffer, null, flushPeriod, flushPeriod); } public void AddResult(T result) { m_buffer.Enqueue(result); Console.WriteLine("Buffer is up to {0} elements", m_buffer.Count); } public void Dispose() { Console.WriteLine("Turning off timer"); m_timer.Dispose(); Console.WriteLine("Flushing final buffer output"); FlushBuffer();
James manning
source share