当多个线程写入同一个文件时会发生什么负面影响?

时间:2012-07-05 17:33:07

标签: c# .net multithreading .net-2.0 integration-testing

以下是失败的集成测试的伪代码:

[测试]

void TestLogger()
    // Init static logger
    Logger.Init(pathToFile);

    // Create five threads that will call LogMessages delegate
    for i = 1 to 5 
    {
       Thread aThread = new Thread(LogMessages)
       aThread.Start(i);
    }

    // let threads complete their work
    Thread.Sleep(30000);

    /// read from log file and count the lines
    int lineCount = GetLineCount();

    // 5 threads, each logs 5 times = 25 lines in the log
    Assert.Equal(25, lineCount);


static void LogMessages( object data )
  // each thread will log five messages
  for i = 1 to 5 
  Logger.LogMessage(i.ToString() + " " + DateTime.Now.Ticks.ToString());
  Thread.Sleep(50);

每次运行测试时,行数似乎都会发生变化。有时行数为23,有时为25。

在我挖掘代码之后,我注意到多个线程同时访问日志文件(通过滴答计数验证相同)。对此文件的访问没有锁定,但同时我看不到抛出任何异常。任何人都可以解释为什么运行之间的日志行数不一致?此外,这是多个线程同时写入同一文件的负面影响吗?

4 个答案:

答案 0 :(得分:5)

竞争条件,就像你在这里一样,众所周知是不可预测的。你永远不知道有多少写不能正常工作 - 有时甚至可能完全正常。是的,这是在没有同步的情况下从多个线程写入同一文件的负面影响。

答案 1 :(得分:1)

如果您正在尝试使用Environment.TickCount验证同时性,那么您将度过一段美好时光。它只有大约15毫秒(IIRC)的精度,所以如果两个线程的值相同,那么你真正知道的是它们相互记录的距离大约是15毫秒。

如果您的Logger类锁定其对日志文件的访问权限,那就足够了。只需通过private static readonly object sync = new object();创建同步对象,然后执行lock (sync) { ... open/read/write the file ... }即可。否则你将受到你正在使用的任何类型的流的线程安全的摆布(提示:通常它们不是线程安全的)。

答案 2 :(得分:1)

处理这些生产者/消费者死锁和其他竞争条件的最简单方法可能是调用内置的lock():

lock(Logger){
 //use your logger here
}

这将阻止其他线程。您也可以使用上面简要提到的同步锁定样式。这个人的网站上提供了所有可用选项(以及优缺点)的一个很好的例子:

http://www.gavindraper.co.uk/2012/02/05/thread-synchronizationlocking-in-net/

祝你好运。

答案 3 :(得分:1)

通常,通过将日志条目(阻止生产者 - 消费者队列)排队到写入磁盘的一个记录器线程来执行multiThreaded日志记录。这使锁定时间缩短到将*日志条目推送到队列所花费的时间:next-to-no contention。队列吸收任何磁盘延迟,网络延迟等。

使用简单锁定会在所有调用线程上造成任何磁盘/网络延迟/延迟。