我有一个文件,它是某些数据的XML表示形式,这些数据来自Web服务并在Web应用程序中本地缓存。我们的想法是,这些数据非常静态,但可能会更改。所以我已将其设置为缓存到文件,并将监视器卡在其上以检查它是否已被删除。删除后,文件将从其源代码刷新并重建。
我现在正在遇到问题,因为很明显在多线程环境中它会因为在读取/写入文件时尝试访问数据而失败。
这让我很困惑,因为我添加了一个要锁定的对象,并且在读/写期间总是被锁定。据我了解,从其他线程尝试访问将被告知“等待”直到锁被释放?
只是为了让你知道,我是多线程开发的新手,所以我完全愿意接受这是我的一个搞砸:)
抱歉 - 我应该说这是使用 ASP.NET 2.0 :)
答案 0 :(得分:6)
以下是我用来确保文件未被其他进程锁定的代码。它并非100%万无一失,但它大部分时间都可以完成工作:
/// <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文件。
答案 1 :(得分:1)
如果你锁定了一个存储为 static 的对象,那么锁应该适用于同一个应用程序域中的所有线程,但是你可能需要上传一个代码示例,这样我们才能拥有看看有问题的台词。
也就是说,一个想法是检查IIS是否配置为以Web Garden模式运行(即执行应用程序的进程超过1个),这会破坏您的锁定逻辑。虽然您可以使用互斥锁来解决这种情况,但是更容易重新配置应用程序以在单个进程中执行,尽管在弄乱Web园设置之前和之后检查性能是明智的,因为它可能会影响性能
答案 2 :(得分:1)
您可以使用临时名称(“data.xml_TMP”)创建文件,并在准备好时将名称更改为应该是的名称。这样,在准备好之前,没有其他进程可以访问它。
答案 3 :(得分:1)
好的,我一直在研究这个问题,最后创建了一个压力测试模块,基本上可以从几个线程(See Related Question)中剔除我的代码。
从这一点开始,在我的代码中找到漏洞要容易得多。事实证明我的代码实际上并不遥远,但是它可以进入某个逻辑路径,这基本上导致读/写操作堆叠,这意味着如果它们没有及时清除,它会热潮!
一旦我把它拿出来,再次进行压力测试,一切正常!
所以,我在文件访问代码中没有真正做任何特殊,只是确保我在适当的时候使用lock
语句(即在读或写时)。 /强>
答案 4 :(得分:0)
如何使用AutoResetEvent
在线程之间进行通信?我创建了一个控制台应用程序,它在createfile
方法中创建了大约8 GB的文件,然后在main
方法中复制该文件
static AutoResetEvent waitHandle = new AutoResetEvent(false);
static string filePath=@"C:\Temp\test.txt";
static string fileCopyPath=@"C:\Temp\test-copy.txt";
static void Main(string[] args)
{
Console.WriteLine("in main method");
Console.WriteLine();
Thread thread = new Thread(createFile);
thread.Start();
Console.WriteLine("waiting for file to be processed ");
Console.WriteLine();
waitHandle.WaitOne();
Console.WriteLine();
File.Copy(filePath, fileCopyPath);
Console.WriteLine("file copied ");
}
static void createFile()
{
FileStream fs= File.Create(filePath);
Console.WriteLine("start processing a file "+DateTime.Now);
Console.WriteLine();
using (StreamWriter sw = new StreamWriter(fs))
{
for (long i = 0; i < 300000000; i++)
{
sw.WriteLine("The value of i is " + i);
}
}
Console.WriteLine("file processed " + DateTime.Now);
Console.WriteLine();
waitHandle.Set();
}