多线程环境中的文件访问策略(Web App)
我有一个文件,该文件是从Web服务获取并在Web应用程序本地缓存的某些数据的XML表示。想法是该数据是非常静态的,但是可能会发生变化。因此,我将其设置为缓存到文件,并在其上放置了一个监视器,以检查该文件是否已删除。删除后,文件将从其源刷新并重建。
不过,我现在遇到了问题,因为显然在多线程环境中,当它仍在读取/写入文件时尝试访问数据时,它会崩溃。
这使我感到困惑,因为我添加了一个要锁定的对象,并且在读取/写入期间始终将其锁定。据我了解,尝试从其他线程进行的访问将被告知"等待",直到锁被释放?
只是让我们知道,我是多线程开发的真正新手,所以我完全愿意接受这对我来说是一个麻烦:)
- 我想念什么吗?
- 在多线程环境中最佳的文件访问策略是什么?
编辑
抱歉,我应该说这是使用ASP.NET 2.0 :)
解决方案
回答
如果我们要锁定存储为静态对象的对象,则该锁定应适用于同一应用程序域中的所有线程,但是也许我们需要上传代码示例,以便我们查看有问题的代码行。
就是说,一种想法是检查IIS是否配置为以Web Garden模式运行(即,执行应用程序的进程超过1个),这会破坏锁定逻辑。尽管我们可以使用互斥锁解决这种情况,但重新配置应用程序以在单个进程中执行将更容易,尽管明智的做法是在破坏Web花园设置之前和之后检查性能,因为它可能会影响表现。
回答
我们可以使用临时名称(" data.xml_TMP")创建文件,并在准备好名称后将其更改为应该使用的名称。这样,在准备就绪之前,没有其他进程可以访问它。
回答
这是我用来确保文件没有被另一个进程锁定的代码。这不是百分百的万无一失,但大多数情况下它都能完成工作:
/// <summary> /// Blocks until the file is not locked any more. /// </summary> /// <param name="fullPath"></param> bool WaitForFile(string fullPath) { int numTries = 0; while (true) { ++numTries; try { // Attempt to open the file exclusively. using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None, 100)) { fs.ReadByte(); // If we got this far the file is ready break; } } catch (Exception ex) { Log.LogWarning( "WaitForFile {0} failed to get an exclusive lock: {1}", fullPath, ex.ToString()); if (numTries > 10) { Log.LogWarning( "WaitForFile {0} giving up after 10 tries", fullPath); return false; } // Wait for the lock to be released System.Threading.Thread.Sleep(500); } } Log.LogTrace("WaitForFile {0} returning true after {1} tries", fullPath, numTries); return true; }
显然,我们可以调整超时和重试以适合应用程序。我用它来处理巨大的FTP文件,这些文件需要花费一些时间来编写。
回答
好的,我一直在努力,最终创建了一个压力测试模块,基本上是从几个线程中剔除我的代码(请参阅"相关问题")。
从这一点开始,在我的代码中发现漏洞要容易得多。事实证明,我的代码实际上并不是遥不可及的,但是有一定的逻辑路径可以进入,基本上导致了读/写操作的堆积,这意味着如果不及时清除它们,它将去繁荣!
一旦取出,再次进行压力测试,一切正常!
因此,我并没有在文件访问代码中做任何特别的事情,只是确保在适当的地方(例如,在读取或者写入时)使用了" lock"语句。