如何调试“共享违规”在尝试删除文件时 [英] How to debug "Sharing Violation" when trying to delete a file

查看:184
本文介绍了如何调试“共享违规”在尝试删除文件时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a multi threaded C# application which creates files, opens them for processing, then deletes them once finished. This application can expect anywhere from 1 - 100 files to be processed. Somewhat randomly (most likely attributed to the multi threaded nature of the application) I get a sharing violation when I try to delete a file after processing. My gut says, well Vic, you didn't properly close/dispose the file before trying to delete it. And I would go with my gut if it happened for every file, but it doesn't. So, I'm trying to find out where I'm making a mistake. Anyone out there have any pointers on how to debug this type of an exception? I would love to see a stack trace on the file if that makes sense.

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

I'll attempt to show pseudo code, however, my question is more on how to debug this type of exception:

应用程序事件:

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

Operation Start += Create new processor.

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

Transfer File += Processor.ProcessFile and Add new Document object to Processor's Document collection (as path, not file)

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

Operation complete += Processor.Aggregate files, create new File containing contents of files. When this method is finished, it calls ProcessorFinished.

处理器事件:

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

Processor Finished += Application_CleanUpProcessor. In this method, I dispose of the processor, which in turn disposes of a document object, which deletes the file.

推荐答案

接受您需要快速验证是否要花更多时间调试代码,或者写得好测试证明你的代码是好的,你想要的是一种快速的方法来证明没有其他进程正在使用你的文件。因此,我们假设:

Accepting that you need a quick way to verify whether or not to spend more time on debugging your code, or maybe writing good tests to prove your code is ok, what you want is a quick way to prove that no other process is using your file. So, lets assume:


  • 您的文件位于本地磁盘(不是网络共享)上,并且

  • 你怀疑防病毒软件,Windows索引或其他东西锁定了你的代码以外的文件

  • 因此你需要一种快速的方法来在编写测试之前将其输入/输出

您希望能够运行您的程序,并查看该文件发生的情况,直至您遇到共享冲突。

You want to be able to run your program, and see what has happened to that file leading up to the point you have a sharing violation.

我会这样做:

Procmon是一款出色的工具,您可以按顺序筛选所有流程中您想要查看的内容。 链接到来自Microsoft的sysinternals的procmon

Procmon is an excellent tool, you can filter down to what you want to see happening across all processes in sequential order. Link to procmon at sysinternals, from Microsoft

打开procmon,为Path添加过滤器以 开头

Open procmon, add a filter for "Path" "begins with" ""

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

Now add a highlight for "Result" "is" "SHARING VIOLATION"

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

And finally, run your program until you get an exception, then right click the file with the sharing violation, in the path column, and select "Include '<filename here>'" to remove all other results. You can now see all activity for the file that caused your exception ...

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

If you want to get comfortable with procmon, here's the code I used to fake this all for you. It has a side thread which locks the file, and a main thread which then tries to lock the file. Just create a C# console app and off you go. It looks like this:

因此,在不到2分钟的时间内,您可以看到您的代码是否有问题或其他原因。我前几天使用它来确定我的Com组件实际上是使用备用文件流,因此在尝试使用网络驱动器时抛出异常。没有多少单元测试会帮助我。

So in less than 2 minutes you can see if its your code at fault, or something else. I used this the other day to determine that my Com component was in fact using alternate file streams, and so threw an exception when it was trying to use a network drive. No amount of unit testing would have helped me there.

以下是强制共享违规的测试代码:

And here is the test code to force a sharing violation:

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();
    }
}

这是所有人!

这篇关于如何调试“共享违规”在尝试删除文件时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆