2012-07-05 57 views
0

下面是一个集成测试失败的伪代码:多线程写入同一文件时会发生什么负面影响?

[测试]

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。

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

回答

5

如您在这里所看到的那样,比赛条件非常不可预知。你永远不知道有多少写入无法正常工作 - 有时甚至可能完全正常工作。是的,这是从多个线程写入同一文件而没有同步的负面影响。

+0

要添加到上面的答案,如果线程1获取A,并将B添加到A.然后线程2进来并获取A,将C添加到它。线程1将AB保存到文件,但因为线程2已经读取了文件,所以当它重写文件时,文件将只包含AC而不是ABC。 – 2012-07-05 17:40:42

1

如果您尝试使用Environment.TickCount验证同时性,那么您的时间将会很糟糕。它只有约15毫秒(IIRC)的准确度,所以如果两个线程的值相同,那么你真正知道的是它们在相互间约15ms内记录。

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

1

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

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

这将在海湾举行的其他线程。您还可以使用上面简要提到的同步锁定样式。有关于这个人的网站上提供的所有选项(和利弊)一个很好的例子:

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

好运。

+0

..并且与简单一起去表现不佳。一个10ms的寻道会产生一个10ms的所有应用程序线程尝试记录 - 一个进入磁盘IO,另一个等待锁定。 – 2012-07-05 20:28:40

1

通常,通过将日志条目(阻塞生产者 - 消费者队列)排队到一个写入磁盘的记录器线程来执行多线程日志记录。这将锁定时间降低到将*日志条目推送到队列所需的时间:即将到来的争用。队列吸收任何磁盘延迟,网络延迟等。

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

相关问题