File stuck open after ThreadAbortException

M

Mark Phillips

Hello,

I am having a problem in which a file can get stuck open when a thread
that is attempting to write to it gets aborted (ThreadAbortedException
occurs). The log file gets stuck open until the process is shut down
(cannot delete file from Windows Explorer, for example). My test
application stops execution with: An unhandled exception of type
'System.IO.IOException' occurred in mscorlib.dll Additional
information: The process cannot access the file "c:\abort_test.txt"
because it is being used by another process.

I figured I was not closing things properly, but I think I'm OK. I
created a simple test application and am still stumped. Here's my code
(added to a visual studio.net 2003 Windows application):

public static void ThreadProc()
{
// Just keep writing to the log file until thread gets aborted
for (; true;)
{
try
{
using ( FileStream fs = File.Open(@"c:\abort_test.txt",
FileMode.Append,FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(DateTime.Now.ToString()+" A line of text");
}
}
}
catch (ThreadAbortException e)
{
using ( FileStream fs = File.Open(@"c:\abort_test2.txt",
FileMode.Append,FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(DateTime.Now.ToString()+ e.Message + "--" +
e.StackTrace);
}
}
}
Thread.Sleep(0);
}
}

private void Form1_Load(object sender, System.EventArgs e)
{
// Sometimes code aborts in non-harmful places, so loop enough
times to almost guarantee a problem
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(ThreadProc));
t.Start();
Thread.Sleep(1000);
t.Abort();
t.Join();
}
}


Here's the contents from my c:\abort_test2.txt:
11/14/2003 3:43:02 PMThread was being aborted.-- at
Microsoft.Win32.Win32Native.CreateFile(String lpFileName, Int32
dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES
securityAttrs, FileMode dwCreationDisposition, Int32
dwFlagsAndAttributes, IntPtr hTemplateFile)
at Microsoft.Win32.Win32Native.UnsafeCreateFile(String lpFileName,
Int32 dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES
securityAttrs, FileMode dwCreationDisposition, Int32
dwFlagsAndAttributes, IntPtr hTemplateFile)
at System.IO.FileStream..ctor(String path, FileMode mode,
FileAccess access, FileShare share, Int32 bufferSize, Boolean
useAsync, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode,
FileAccess access, FileShare share)
at System.IO.File.Open(String path, FileMode mode, FileAccess
access, FileShare share)
at System.IO.File.Open(String path, FileMode mode, FileAccess
access)
at TestFileAbortProblem.Form1.ThreadProc() in
c:\programs\dotnet\testing\testfileabortproblem\testfileabortproblem\form1.cs:line
98

Any ideas on how I can make sure the file gets closed or how I can
prevent the ThreadAbortException exception from being thrown during
file manipulation?

Thanks in advance,
Mark
 
J

junk

[This followup was posted to microsoft.public.dotnet.framework and a
copy was sent to the cited author.]

Hello,

I am having a problem in which a file can get stuck open when a thread
that is attempting to write to it gets aborted (ThreadAbortedException
occurs). The log file gets stuck open until the process is shut down
(cannot delete file from Windows Explorer, for example). My test
application stops execution with: An unhandled exception of type
'System.IO.IOException' occurred in mscorlib.dll Additional
information: The process cannot access the file "c:\abort_test.txt"
because it is being used by another process.

I figured I was not closing things properly, but I think I'm OK. I
created a simple test application and am still stumped. Here's my code
(added to a visual studio.net 2003 Windows application):

public static void ThreadProc()
{
// Just keep writing to the log file until thread gets aborted
for (; true;)
{
try
{
using ( FileStream fs = File.Open(@"c:\abort_test.txt",
FileMode.Append,FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(DateTime.Now.ToString()+" A line of text");
}
}
}
catch (ThreadAbortException e)
{
using ( FileStream fs = File.Open(@"c:\abort_test2.txt",
FileMode.Append,FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(DateTime.Now.ToString()+ e.Message + "--" +
e.StackTrace);
}
}
}
Thread.Sleep(0);
}
}

private void Form1_Load(object sender, System.EventArgs e)
{
// Sometimes code aborts in non-harmful places, so loop enough
Use a finally clause to close the file.
 
B

Brian Grunkemeyer

Using Thread.Abort like this is fundamentally broken, and cannot be fixed
short of introducing some powerful reliability primitives. If a thread is
running FileStream's Dispose method in a finally block and you abort the
thread, you will leak a handle. Given the Everett CLR, there is no change
I can make to FileStream or your code to avoid this problem. In our
Whidbey release, we have SafeHandle and we're designing constrained
execution regions to work around some of these issues. But the complexity
of constrained execution regions will put them out of reach of many users,
and they are inappropriate for the vast majority of code. Fundamentally,
you should not be using Thread.Abort like this. Please consider using some
other synchronization mechanism for your threads - Thread.Abort isn't a
good API for user code to call, since there's a good chance you must unload
the entire appdomain immediately afterwards.

For a bit more on why Thread.Abort is bad, see Chris Brumme's blog.
http://blogs.gotdotnet.com/cbrumme/PermaLink.aspx/dac5ba4a-f0c8-42bb-a5cf-09
7efb25d1a9

If that isn't enough, look for his entry on our exception model. It's
long, but will discuss most of the interesting issues, such as interrupting
a thread between any machine instruction.

Brian Grunkemeyer
..NET Framework Base Class Library team
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top