How to debug "Sharing Violation" when trying to delete a file How to debug "Sharing Violation" when trying to delete a file multithreading multithreading

How to debug "Sharing Violation" when trying to delete a 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:

  • Your file is on local disk (not a network share), and
  • you suspect that antivirus, windows indexing or something else is locking the file other than your code
  • therefore you need a quick way to qualify that in/out before writing tests

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.

I would do this:

1. Download ProcMon from sysinternals (10 seconds)

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

2. Extract and run Procmon, add filters and highlights (30 seconds)

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

Adding a filter to procmon

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

Add a Sharing Violation filter

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 showing who locked that file

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:

Here's one I made earlier - the lock and lock again culprit

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

That's all folks!