Reputation: 127
Okay so my program has around 30 threads, and I need to make a log of some of the information gathered through each threads.
The way I did this is by: Creating a public static StringBuilder in the class Program, and then each thread will call the AppendLine method to this StringBuilder instance every few minutes. Then, every 30 minutes another Thread dedicated to writing using a StreamWriter does exactly that.
For example:
public class Program
{
public static StringBuilder sb = new StringBuilder();
public static void Main(string[] args)
{
// Start all threads
}
}
public class Example
{
Thread t1 = new Thread(() =>
{
while(true)
{
DoSomething();
}
});
Thread logThread = new Thread(() =>
{
while(true)
{
using(StreamWriter writer = new StreamWriter(Path))
{
writer.Write(Program.sb);
}
}
});
public static void DoSomething()
{
// Will do something for a few minutes.
Program.sb.AppendLine("Some text gathered before...different everytime!");
}
}
Is this a okay way of doing this?
Thanks
Upvotes: 2
Views: 7239
Reputation: 7150
We can use ReaderWriterLockSlim http://www.johandorper.com/log/thread-safe-file-writing-csharp
private static ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();
public void WriteToFile(string text, string path)
{
_readWriteLock.EnterWriteLock();
using (StreamWriter sw = new StreamWriter(path, true))
{
sw.WriteLine(text);
sw.Close();
}
_readWriteLock.ExitWriteLock();
}
Upvotes: 3
Reputation: 1285
If you are using .Net framework v4 or above, take a look at the data structures in the System.Collections.Concurrent
Namespace; particularly, the BlockingCollection<T>
Class. The BlockingCollection has some useful methods like TakeFromAny
typically designed to serve a producer - consumer scenario such as the one you describe.
Upvotes: 0
Reputation: 33139
I would suggest not having each of those threads write to the file, but write to a shared memory resource instead (a Singleton that you can access from every thread), and then have that Singleton write to the file ONLY when necessary -- say, at the end of your program. That way only one thread accesses I/O and you'll be much safer.
Obviously the Singleton you write must be thread-safe too, so you must control writes to it with a lock.
Good luck!
Upvotes: 0
Reputation: 700152
No, the StringBuilder
is not thread safe, so multiple threads using it at the same time may corrupt it.
Synchronise the access to the StringBuilder
using the lock
keyword. Make it private, and supply public methods to work with it safely:
private static StringBuilder _sb = new StringBuilder();
private static object _sbSync = new Object();
public static void AppendLine(string line) {
lock (_sbSync) {
_sb.appendLine(line);
}
}
public static string GetLines() {
lock (_sbSync) {
string result = _sb.ToString();
_sb = new StringBuilder();
return result;
}
}
Upvotes: 3