Reputation:
I have the following code inside my asp.net mvc-5 web application :-
System.IO.StreamWriter file =
new System.IO.StreamWriter(Server.MapPath("~/logs/logs.txt"), true);
await file.WriteLineAsync("execution started at " + System.DateTime.Now.ToString());
file.Close();
now my question what will happen if 2 methods execute the above code at the same time? will one of them fail ? since it will be trying to write to the txt file which is being accessed by another thread ?
Upvotes: 0
Views: 3644
Reputation: 120410
You can leverage TPL Dataflow to do this very nicely for you such that you get a queue and a mechanism by which writes to the file never occur in parallel (by using MaxDegreeOfParallelism
)
public class Logger
{
private ActionBlock<string> block;
public Logger(string filePath)
{
block = new ActionBlock<string>(async message => {
using(var f = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
f.Position = f.Length;
using(var sw = new StreamWriter(f))
{
await sw.WriteLineAsync(message);
}
}
}, new ExecutionDataflowBlockOptions{MaxDegreeOfParallelism = 1});
}
public void Log(string message)
{
block.Post(message);
}
}
Upvotes: 4
Reputation: 127543
When you open StreamWriter
with a string it does the following to create the stream
private static Stream CreateFile(String path, bool append, bool checkHost) {
FileMode mode = append? FileMode.Append: FileMode.Create;
FileStream f = new FileStream(path, mode, FileAccess.Write, FileShare.Read,
DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost);
return f;
}
Because it does FileAccess.Write, FileShare.Read
that means it is asking for write permission and only allow other people to open the file if they are asking for read permission. Because both calls will be asking for write permission the 2nd call will fail with a "file in use" error.
A way to work around this issue is use a SemaphoreSlim to block access to the file, this will only allow one writer at a time.
//Elsewhere
private static SemaphoreSlim _fileLock = new SemaphoreSlim(1);
//In your function.
try
{
await _fileLock.WaitAsync();
using(var file = new System.IO.StreamWriter(Server.MapPath("~/logs/logs.txt"), true))
{
await file.WriteLineAsync("execution started at " + System.DateTime.Now.ToString());
}
}
finally
{
_fileLock.Release();
}
However a even better solution is just find a 3rd party logging library that can handle this for you like Log4Net, then you don't need to worry about the locking or concurrency.
Upvotes: 2
Reputation: 3599
Yes. You will get an error that the file is in use by another process. Your best bet is to surround that block withtry catch
and handle the exception then retry once the file is available.
Upvotes: 0