【问题标题】:Synchronize writing to a file at file-system level在文件系统级别同步写入文件
【发布时间】:2011-02-18 18:35:50
【问题描述】:

我有一个文本文件,多个线程/进程将写入它(它是一个日志文件)。

文件有时会因为并发写入而损坏。

我想从所有线程中使用文件写入模式,该模式在文件系统级别本身是顺序的。

我知道可以使用锁(用于多个进程的互斥锁)并同步写入此文件,但我更喜欢以正确的模式打开文件并将任务留给System.IO

有可能吗?这种情况的最佳做法是什么?

【问题讨论】:

  • 所有进程是否都在同一台机器上运行,或者您正在访问网络共享上的文件?
  • 我不认为(但我不是 100% 肯定)有办法以“等待直到它可以锁定”类型的共享模式打开文件.我认为做你想做的事情的唯一方法是使用互斥锁。当然,如果您在网络共享上打开文件,这也不是解决方案,您可能需要设置一个服务器来接收日志调用。
  • @Lasse:同一台机器上的所有线程/进程(Windows)

标签: c# concurrency filesystems writing


【解决方案1】:

您最好的选择就是使用锁/互斥锁。这是一种简单的方法,很有效,您可以轻松理解和推理。

在同步方面,从最简单的可行解决方案开始通常是值得的,并且只有在遇到问题时才尝试改进。

【讨论】:

  • 其实我对写作的控制力不够。我使用Debug.Write,然后使用Flush,但似乎内容并未恰好在Flush 之后写入磁盘。但我可以选择打开/共享模式和.NET writer 对象(现在我使用TextWriter
  • @Xaqron 我认为您可以很容易地切换到打开、刷新和关闭文件的文件写入机制。但是,性能是否足够取决于您希望记录的速率,以及您希望表示来自不同进程的交错的准确度。
【解决方案2】:

据我所知,Windows 没有您想要的。没有文件句柄对象通过在写入文件时阻止所有其他用户来自动同步。

如果您的日志记录涉及打开文件、写入、关闭文件三个步骤,那么您可以让您的线程尝试以独占模式(FileShare.None)打开文件,如果无法打开则捕获异常,然后尝试再次直到成功。我发现这充其量是乏味的。

在我的从多个线程记录的程序中,我创建了一个TextWriter 后代,它本质上是一个队列。线程调用该对象上的WriteWriteLine 方法,这些方法格式化输出并将其放入队列中(使用BlockingCollection)。一个单独的日志线程服务于队列——从中拉出东西并将它们写入日志文件。这有几个好处:

  • 线程不必为了记录而相互等待
  • 只有一个线程正在写入文件
  • 轮换日志很简单(即每小时启动一个新日志文件等)
  • 出错的可能性为零,因为我忘记对某个线程进行锁定

跨进程执行此操作会困难得多。我什至从未考虑过尝试跨进程共享日志文件。如果我需要它,我会创建一个单独的应用程序(一个日志服务)。该应用程序将执行实际的写入,而其他应用程序则传递要写入的字符串。同样,这确保了我不会搞砸事情,并且我的代码保持简单(即客户端中没有显式锁定代码)。

【讨论】:

  • 如果我无法在文件系统级别解决它,那么对于 multi-process 场景需要使用 IPC,这对于简单的记录器来说不是一个好方法(我认为著名的记录器不会这样做那样工作)。
  • 我同意它不太理想,但文件系统级别似乎没有任何自动同步。我可能是错的,但是仔细阅读相关文档并没有发现任何问题。如果您遇到什么,请告诉我们。另外,你说的是什么“著名的伐木工”?
【解决方案3】:

您可以使用File.Open() 并将FileShare 值设置为None,并让每个线程在无法访问文件时等待。

【讨论】:

  • 我认为这会导致访问异常,除非有阻塞调用或等待句柄。
  • 那确实会引发异常。
  • @Xaqron 目前无法测试,如果您尝试,请告诉我它的作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
相关资源
最近更新 更多