VFe*_*ein 12 c# io multithreading ioexception delete-file
我有一个多线程C#应用程序,它创建文件,打开它们进行处理,然后在完成后删除它们.此应用程序可以处理1到100个文件.有点随机(很可能归因于应用程序的多线程特性)当我尝试在处理后删除文件时,我收到了共享冲突.我的直觉说,维克,在尝试删除文件之前,你没有正确关闭/处理文件.如果它发生在每个文件中,我会坚持我的直觉,但事实并非如此.所以,我试图找出我犯了错误的地方.那里的任何人都有关于如何调试这种类型的异常的指示?如果有意义,我很乐意在文件上看到堆栈跟踪.
我将尝试显示伪代码,但是,我的问题更多的是如何调试这种类型的异常:
应用事件:
操作开始 + =创建新处理器.
传输文件 + = Processor.ProcessFile并将新的Document对象添加到处理器的文档集合(作为路径,而不是文件)
操作完成 + = Processor.Aggregate files,创建包含文件内容的新文件.完成此方法后,它将调用ProcessorFinished.
处理器事件:
处理器已完成 + = Application_CleanUpProcessor.在这种方法中,我处理了处理器,处理器又处理了一个删除文件的文件对象.
And*_*own 30
接受您需要快速验证是否花费更多时间来调试代码,或者编写好的测试来证明您的代码是正常的,您想要的是一种快速的方法来证明没有其他进程正在使用您的文件.所以,让我们假设:
您希望能够运行您的程序,并查看该文件发生了什么,导致您遇到共享冲突.
我会这样做:
Procmon是一个很好的工具,您可以按顺序过滤到您希望在所有流程中看到的内容.链接到来自Microsoft的sysinternals的procmon
打开procmon,为"Path"添加过滤器"以"开头"""

现在为"结果"添加一个突出显示"是""共享违规"

最后,运行程序直到出现异常,然后右键单击路径列中包含共享冲突的文件,并选择"包括'< filename here >'"以删除所有其他结果.您现在可以看到导致您的异常的文件的所有活动......

如果你想熟悉procmon,这里是我用来为你假装这一切的代码.它有一个用于锁定文件的侧线程,以及一个然后尝试锁定文件的主线程.只需创建一个C#控制台应用程序即可.它看起来像这样:

因此,在不到2分钟的时间内,您可以看到它的代码是否有问题,或者其他什么.我前几天使用它来确定我的Com组件实际上是使用备用文件流,因此在尝试使用网络驱动器时抛出异常.没有多少单元测试会帮助我.
以下是强制共享违规的测试代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
internal class Program
{
private static int lockPoint = 0;
private static void Main(string[] args)
{
const string testFile = @"H:\test\test.txt";
FileInfo testFileInfo = new FileInfo(testFile);
if (!testFileInfo.Directory.Exists)
{
testFileInfo.Directory.Create();
}
// Clear our example
if (testFileInfo.Exists)
{
testFileInfo.Delete();
}
// Create the test file
using (FileStream fs = File.Create(testFile))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine("test file content");
}
Task iLockTheFileFirst = new Task(() => {
using (FileStream fsThread = File.Open(testFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
Console.WriteLine("iLockTheFileFirst: I opened the file");
// Set lockPoint to 1 and let main try and open the file
Interlocked.Exchange(ref lockPoint, 1);
// Wait until the main thread sets lockPoint to 3
const int ifEqualTo3 = 3;
const int replaceWith4 = 4;
while (Interlocked.CompareExchange(ref lockPoint, replaceWith4, ifEqualTo3) != ifEqualTo3)
{
Console.WriteLine("iLockTheFileFirst: Waiting for main thread to let me finish");
Thread.Sleep(1000);
}
}
Console.WriteLine("iLockTheFileFirst: I have closed the file");
});
// Start the thread and lock the file
iLockTheFileFirst.Start();
// Now spin until the lockPoint becomes 1
const int ifEqualTo1 = 1;
const int replaceWith2 = 2;
// If lockPoint is equal to 1 (i.e. the main thread wants us to finish), then move it to 2
while (Interlocked.CompareExchange(ref lockPoint, replaceWith2, ifEqualTo1) != ifEqualTo1)
{
Console.WriteLine("Main thread: waiting for iLockTheFileFirst to open the file");
Thread.Sleep(1000);
}
try
{
Console.WriteLine("Main thread: now I'll try opening the file");
using (FileStream fsMain = File.Open(testFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
Console.WriteLine("Main thread: I opened the file, which shouldn't be possible");
}
}
catch (IOException ioex)
{
Console.WriteLine("Main thread: IOException: " + ioex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Main thread: some other exception: " + ex.Message);
}
// Set lockPoint to 3 and let other thread finish
Interlocked.Exchange(ref lockPoint, 3);
// Wait for other thread to finish
const int ifEqualTo4 = 4;
const int replaceWith5 = 5;
while (Interlocked.CompareExchange(ref lockPoint, replaceWith5, ifEqualTo4) != ifEqualTo4)
{
Thread.Sleep(10);
}
Console.WriteLine("Main thread: Press enter to finish");
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
这就是所有人!