I need to read a number from a file and then increment the number and update the same file just for debugging purposes. I wrote this code and to my surprise it throws an exception (it is just for debugging but nonetheless I would like to get to the bottom of this):
The process cannot access the file '' because it is being used by another process.
Code:
string path = Server.MapPath("~/Log.txt");
int newTotal = 0;
using (var reader = new StreamReader(path))
{
var total = reader.ReadLine();
if (total != null)
{
newTotal = int.Parse(total) + 1;
}
}
using (var writer = new StreamWriter(path, false))
{
// I added AutoFlush because I read somewhere on SO
// this will write to disk immediately
writer.AutoFlush = true;
writer.Write(newTotal);
}
Then I wanted to narrow the issue down to either reading or writing, so I did this:
string path = Server.MapPath("~/Log.txt");
int newTotal = 0;
try
{
using (var reader = new StreamReader(path))
{
var total = reader.ReadLine();
if (total != null)
{
newTotal = int.Parse(total) + 1;
}
}
}
catch (Exception)
{
throw new System.Web.HttpException("During reading...");
}
try
{
using (var writer = new StreamWriter(path, false))
{
writer.AutoFlush = true;
writer.Write(newTotal);
}
}
catch (Exception)
{
throw new System.Web.HttpException("During writing...");
}
I am getting this so this tells me it happens during both but randomly:
During reading...
During writing...
During reading...
During writing...
During reading...
During reading...
During writing...
During writing...
During writing...
During writing...
During writing...
During reading...
During reading...
During reading...
Just a note that this code is in the Controller
of an MVC app within this method:
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
// Code is here
}
I used Process Explorer and nothing else is using the file.
Question : I am disposing things here so why the exception?
At first I thought perhaps there is a delay in disposing the reader
but in that case all exceptions should be about reader
but this is not the case. Also, below will also give the same exception:
this.path = Server.MapPath("~/Log.txt");
var total = System.IO.File.ReadAllText(this.path);
int newTotal = 0;
if (total != null)
{
newTotal = int.Parse(total) + 1;
}
System.IO.File.WriteAllText(this.path, newTotal.ToString());
There are no threads. Just HTTP GET (regular and via AJAX).
EDIT
This happens during load testing using Visual Studio 2015.
I've run into this problem and I solved it by adding a while loop.
Try doing this and see if it solves your problem.
using (var reader = new StreamReader(path))
{
while (reader.Peek() > -1)
{
var total = reader.ReadLine();
newTotal = int.Parse(total) + 1;
}
}
The issue is NOT because of:
reader
is collected. I tested the exact code with a console application and the issue cannot be replicated. static
), then they obviously will not be threadsafe. They will be shared. But this code is not within a static context. Here is the caveat:
When using a browser, this issue was never replicated. I also did something simple like this:
protected override void Initialize(RequestContext requestContext)
{
System.IO.File.AppendAllText(tPath, "Thread enter and ID is: " +
System.Threading.Thread.CurrentThread.ManagedThreadId + Environment.NewLine);
// Placed all code here
System.IO.File.AppendAllText(tPath, "Thread exit and ID is: " +
System.Threading.Thread.CurrentThread.ManagedThreadId + Environment.NewLine);
}
Now with the above code, when the requests are made through a browser, as expected, the contents of the file are as shown below. Notice every entry is synchronous :
Thread enter and ID is: 35
Thread exit and ID is: 35
Thread enter and ID is: 11
Thread exit and ID is: 11
Thread enter and ID is: 29
Thread exit and ID is: 29
Thread enter and ID is: 36
Thread exit and ID is: 36
Thread enter and ID is: 27
Thread exit and ID is: 27
Thread enter and ID is: 11
Thread exit and ID is: 11
Thread enter and ID is: 29
Thread exit and ID is: 29
Thread enter and ID is: 8
Thread exit and ID is: 8
Thread enter and ID is: 11
Thread exit and ID is: 11
Thread enter and ID is: 36
Thread exit and ID is: 36
...
But during Visual Studio load testing, the contents are like this and the entry into the method is not synchronous :
Thread enter and ID is: 12
Thread exit and ID is: 12
Thread enter and ID is: 29
Thread enter and ID is: 49
Thread enter and ID is: 51
Thread exit and ID is: 29
Thread exit and ID is: 51
Thread enter and ID is: 48
Thread exit and ID is: 48
Thread enter and ID is: 57
Thread exit and ID is: 57
Thread enter and ID is: 17
Thread exit and ID is: 17
Thread enter and ID is: 55
Thread exit and ID is: 55
Thread enter and ID is: 42
Thread exit and ID is: 42
Thread enter and ID is: 47
Thread enter and ID is: 55
...
Conclusion
In conclusion, when doing a load test with Visual Studio, the call behavior is not the exact same as it would be from a browser. For some reason, each thread is not given its own instance of the class. I have no idea why but if someone does, please chime in. I think this is bullcrap if you ask me: How can I do a load test if it is doing something which is totally against the ASP.NET architecture?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.