2

好的,所以我的程序有大约 30 个线程,我需要记录通过每个线程收集的一些信息。

我这样做的方法是:在类 Program 中创建一个公共静态 StringBuilder,然后每个线程每隔几分钟就会调用这个 StringBuilder 实例的 AppendLine 方法。然后,每隔 30 分钟,另一个专用于使用 StreamWriter 进行写入的线程就会这样做。

例如:

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!");
    }
}

这是这样做的好方法吗?

谢谢

4

4 回答 4

3

不,StringBuilder它不是线程安全的,因此同时使用它的多个线程可能会损坏它。

StringBuilder使用lock关键字同步访问。将其设为私有,并提供公共方法以安全地使用它:

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;
  }
}
于 2013-09-21T13:03:26.797 回答
3

我们可以使用 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();
}
于 2014-11-10T05:04:42.093 回答
0

我建议不要让这些线程中的每一个都写入文件,而是写入共享内存资源(您可以从每个线程访问的单例),然后仅在必要时让该单例写入文件 - 比如说,在你的程序结束时。这样只有一个线程访问 I/O,你会更安全。

显然,您编写的 Singleton 也必须是线程安全的,因此您必须使用锁来控制对它的写入。

祝你好运!

于 2013-09-21T13:12:04.543 回答
0

如果您使用的是 .Net framework v4 或更高版本,请查看System.Collections.ConcurrentNamespace中的数据结构;特别是BlockingCollection<T>Class。BlockingCollection 有一些有用的方法,例如TakeFromAny通常设计用于服务生产者 - 消费者场景,例如您描述的场景。

于 2013-09-21T14:25:49.027 回答