Previously I wrote the article Write to file from multiple threads async with C# and .NET Core, which explains how to use a ConcurrentQueue to append lines to a text file. And the ConcurrentQueue is great for the fire-and-forget scenarios of log file writing, where you really do not read from the files you write.
But if you are reading the files you are writing, you need some kind of locking mechanism to ensure that the code block reading and writing the file are accessed by one thread at a time.
There are many options including lock, semaphors and ReaderWriterLock. In this article I will use the good old Mutex class.
STEP 1: THE CODE
using System;
using System.Threading;
using System.IO;
public class ThreadSafeFileWriter
{
public string ReadFile(string filePathAndName)
{
// This block will be protected area
using (var mutex = new Mutex(false, filePathAndName.Replace("\\", "")))
{
var hasHandle = false;
try
{
// Wait for the muted to be available
hasHandle = mutex.WaitOne(Timeout.Infinite, false);
// Do the file read
if (!File.Exists(filePathAndName))
return string.Empty;
return File.ReadAllText(filePathAndName);
}
catch (Exception)
{
throw;
}
finally
{
// Very important! Release the mutex
// Or the code will be locked forever
if (hasHandle)
mutex.ReleaseMutex();
}
}
}
public void WriteFile(string fileContents, string filePathAndName)
{
using (var mutex = new Mutex(false, filePathAndName.Replace("\\", "")))
{
var hasHandle = false;
try
{
hasHandle = mutex.WaitOne(Timeout.Infinite, false);
if (File.Exists(filePathAndName))
return;
File.WriteAllText(filePathAndName, fileContents);
}
catch (Exception)
{
throw;
}
finally
{
if (hasHandle)
mutex.ReleaseMutex();
}
}
}
}
SO WHAT’S UP WITH THE MUTEX?
The Mutex will let threads wait for the mutex handle in a queue until the mutex is released. So if 3 threads will write to the same file, they will wait in line nicely until they are granted access.
It is very important that the code releases the mutex as well, or the code will be locked forever.
Mutexes can be named, like in the example above. This locks the shared resource system wide. So if another process tries to access the same code, that process will also wait in line. Backslashes in mutex names are a reserved character and must be removed.
Taht’s it. You are now a multi-thread expert. Happy coding.
MORE TO READ:
- Write to file from multiple threads async with C# and .NET Core by briancaos
- Semaphores don’t have owners by Raymond Chen
- Mutex class from Microsoft
- TextWriter.Synchronized(TextWriter) Method from Microsoft
- Thread-safe acces to a text file from CodeProject
You missed an exclamation mark in your write file method when checking if the file exists:
Replace –> if (File.Exists(filePathAndName)) with if (!File.Exists(filePathAndName))
LikeLike