【问题标题】:What negative effect will happen when multiple threads write to the same file?当多个线程写入同一个文件时会产生什么负面影响?
【发布时间】:2012-07-05 17:33:06
【问题描述】:

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

[测试]

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。

在深入研究代码后,我注意到日志文件正在被多个线程同时访问(通过滴答计数相同来验证)。对此文件的访问没有锁定,但同时我没有看到抛出异常。谁能解释为什么运行之间的日志行数不一致?此外,这是否是多个线程同时写入同一个文件的负面影响?

【问题讨论】:

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


    【解决方案1】:

    正如您在此处所看到的,众所周知,比赛条件是不可预测的。你永远不知道有多少写入不能正常工作——有时它甚至可能完全正常工作。是的,这是在不同步的情况下从多个线程写入同一个文件的负面影响。

    【讨论】:

    • 添加到上面的答案,如果线程 1 获取 A,并将 B 添加到 A。然后线程 2 进来并获取 A,将 C 添加到它。线程 1 将 AB 保存到文件,但是由于线程 2 已经读取了文件,所以当它重写文件时,文件将只包含 AC 而不是 ABC。
    【解决方案2】:

    如果您尝试使用 Environment.TickCount 验证同时性,您将会遇到麻烦。它只有大约 15 毫秒 (IIRC) 的准确度,因此如果两个线程的值相同,那么您真正知道的就是它们的日志记录彼此相差约 15 毫秒。

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      祝你好运。

      【讨论】:

      • .. 与简单性相去甚远。 10 毫秒的寻道将导致所有尝试登录的应用线程阻塞 10 毫秒 - 进入的线程正在等待磁盘 IO,其他线程正在等待锁定。
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        • 2015-05-26
        • 1970-01-01
        • 2011-03-15
        • 1970-01-01
        • 2012-07-17
        • 2021-06-23
        相关资源
        最近更新 更多