【问题标题】:How to debug "Sharing Violation" when trying to delete a file尝试删除文件时如何调试“共享冲突”
【发布时间】:2013-03-05 06:09:54
【问题描述】:

我有一个多线程 C# 应用程序,它创建文件、打开它们进行处理,然后在完成后删除它们。此应用程序可以预期处理 1 到 100 个文件。有点随机(很可能归因于应用程序的多线程性质)当我在处理后尝试删除文件时遇到共享冲突。我的直觉说,维克,您在尝试删除文件之前没有正确关闭/处置文件。如果每个文件都发生这种情况,我会顺其自然,但事实并非如此。所以,我试图找出我在哪里犯了错误。那里的任何人都对如何调试这种类型的异常有任何指示?如果有意义的话,我很想看到文件上的堆栈跟踪。

我将尝试显示伪代码,但是,我的问题更多是关于如何调试这种类型的异常:

应用程序事件:

操作开始 += 创建新处理器。

传输文件 += Processor.ProcessFile 并将新的 Document 对象添加到 Processor 的 Document 集合中(作为路径,而不是文件)

操作完成 += Processor.Aggregate 文件,创建包含文件内容的新文件。当此方法完成时,它会调用 ProcessorFinished。

处理器事件:

处理器完成 += Application_CleanUpProcessor。在这个方法中,我处置了处理器,而处理器又处置了一个删除文件的文档对象。

【问题讨论】:

  • 任何(部分)代码要显示?单个工作线程会发生这种情况吗?
  • 你知道文件名吗?
  • 只是扮演魔鬼的拥护者,如果您在同一个应用程序中执行所有这些(创建、处理和删除),那么为什么不只在内存中执行所有这些操作。或者如果需要持久性,为什么不使用比文件系统更适合这种事情的数据库?
  • 我首先尝试在内存中完成这一切,在调用内存异常之前,大约 50 个文件的应用程序膨胀到超过 1.5 GB 的内存。那是不行的。当我切换到基于 IO 的时候,应用程序消耗了最多 100mb 的内存。
  • @VFein 能否显示完整的异常消息以及任何内部异常...

标签: c# multithreading io ioexception delete-file


【解决方案1】:

接受您需要一种快速的方法来验证是否要花费更多时间来调试代码,或者编写好的测试来证明您的代码是可以的,您想要的是一种快速的方法来证明没有其他过程是使用您的文件。所以,让我们假设:

  • 您的文件位于本地磁盘(不是网络共享)上,并且
  • 您怀疑防病毒、Windows 索引或其他东西锁定了您的代码以外的文件
  • 因此,在编写测试之前,您需要一种快速的方法来限定输入/输出

您希望能够运行您的程序,并查看导致您遇到共享冲突时该文件发生了什么情况。

我会这样做:

1。从 sysinternals 下载 ProcMon(10 秒)

Procmon 是一款出色的工具,您可以筛选出您希望在所有进程中按顺序看到的情况。 Link to procmon at sysinternals, from Microsoft

2。提取并运行 Procmon,添加过滤器和高光(30 秒)

打开procmon,为“Path”添加一个过滤器“begins with”“

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

最后,运行程序直到出现异常,然后右键单击路径列中存在共享冲突的文件,然后选择“在此处包含'文件名>'”以删除所有其他结果。您现在可以查看导致异常的文件的所有活动...

如果您想熟悉 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();
    }
}

就是这样!

【讨论】:

  • 既然您有更多的代表,也许您可​​以解决图像问题?
猜你喜欢
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
  • 2021-01-10
  • 1970-01-01
相关资源
最近更新 更多