Using Parallel and ThreadPool / QueueUserWorkItem in Combination with Writing / Locking Files

If you’ve wanted to combine parallel / multi-threading and also writing to files, you’ve probably experienced the issue of a file being locked when another process is writing at the same time. Something like:

An unhandled exception of type ‘System.IO.IOException’ occurred in mscorlib.dll

Additional information: The process cannot access the file ‘c:\yourfile’ because it is being used by another process.

One of the ways to get around this is utilize the “lock” statement.

In my below example, I’m running parallel tasks (including the optional MaxDegreeOfParallelism) and writing to a file. I also added a stopwatch and a .sleep to add time and debugging to the method. If you were to remove the lock() from the below, you should experience the ioexception.

Hope this helps as you create parallel tasks (so many great uses) and write files (maybe some simple logging, etc.)

You can also download the sample here.

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace parallelTasks_Example
{
    //custom object for passing to queue task
    public class UpdateFile
    {
        public string lineData { get; set; }

        public string filePath { get; set; }

        public long timeTaken { get; set; }
    }

    internal class Program
    {
        //set an update to use a lock
        private static object fileLock = new object();

        private static void Main(string[] args)
        {
            //just for testing
            Stopwatch timer = new Stopwatch();

            timer.Reset();

            //get some data
            string[] contacts = { "jon", "jon2", "aaron", "efren", "diedrich", "tina", "sandy", "haylie", "trevor", "shondrella" };

            //do something with the data
            timer.Start();
            Parallel.ForEach(contacts, new ParallelOptions { MaxDegreeOfParallelism = 3 }, contact =>
                {
                    //do the task
                    Console.WriteLine(contact + " " + timer.ElapsedMilliseconds);
                    //create an object to past to the queue item
                    UpdateFile fileupdate = new UpdateFile { filePath = @"c:\temp\temp.txt", lineData = contact, timeTaken = timer.ElapsedMilliseconds };
                    //add the queue item
                    ThreadPool.QueueUserWorkItem(UpdateFile, fileupdate);
                });

            Console.ReadLine();
        }

        private static void UpdateFile(object fileData)
        {
            //set object to be locked
            lock (fileLock)
            {
                //get the file
                using (var fw = File.AppendText(((UpdateFile)fileData).filePath))
                {
                    //write the data
                    fw.WriteLine(((UpdateFile)fileData).lineData + ": " + ((UpdateFile)fileData).timeTaken.ToString());
                    //make process take long (for example)
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    }
}
Using Parallel and ThreadPool / QueueUserWorkItem in Combination with Writing / Locking Files

Checking if a file is locked in C# using Win32

Below is a simple, fast way you can check if a file is locked, using Interop to use a win32 function. I’ve found this method to be pretty fast, but I would caution, you should still have some error logic in your code in case in the window of time between you checking your file for availability and using your file, it should become locked. Below is the c# code:

Using:

using System;
using System.IO;
using System.Runtime.InteropServices;

And in your class:

  [DllImport("kernel32.dll")]
        private static extern Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(string lpFileName, System.UInt32 dwDesiredAccess, System.UInt32 dwShareMode, IntPtr pSecurityAttributes, System.UInt32 dwCreationDisposition, System.UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);

        private static readonly uint GENERIC_WRITE = 0x40000000;
        private static readonly uint OPEN_EXISTING = 3;

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(SafeHandle hObject);

        public static bool boolFileLocked(string fPath)
        {
            if (!File.Exists(fPath))
            {
                return false;
            }

            SafeHandle sHandle = null;

            try
            {
                sHandle = CreateFile(fPath, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

                bool inUse = sHandle.IsInvalid;

                return inUse;
            }
            finally
            {
                if (sHandle != null)
                {
                    CloseHandle(sHandle);
                }
            }
        }

To test, toss this into your Main:

long tStart = DateTime.Now.Ticks;
Console.WriteLine("start");
Console.WriteLine(boolFileLocked(@"c:\locked.xlsx"));
Console.WriteLine(string.Format("{0:n0}", DateTime.Now.Ticks - tStart));
tStart = DateTime.Now.Ticks;
Console.WriteLine(boolFileLocked(@"c:\unlocked.xls"));
Console.WriteLine(string.Format("{0:n0}", DateTime.Now.Ticks - tStart));
tStart = DateTime.Now.Ticks;
Console.WriteLine(boolFileLocked(@"c:\missing.xls"));
Console.WriteLine(string.Format("{0:n0}", DateTime.Now.Ticks - tStart));
Console.WriteLine("end");
Console.ReadLine();
Checking if a file is locked in C# using Win32