Geeks With Blogs
Greg Young Greg.ToString()

Thread.Abort can cause some nasty nasty behaviors as it forces an exception where one was not originally intending to be handled. This can wreak havoc when dealing with un-managed resources. I have for your viewing pleasure an example directly from the 1.1 framework! This particular bit of code is from FileStream's constructor! If thread aborts happen at correct times the file stays locked until the process is restarted without any hope of being recoverred. The time that this can occur is specifically in between the time it gets back a handle from the CreateFile etc call and before it wraps it in a handle protector if the exception happens the handle is not yet protected, nor is it closed ... The behavior shown is that the file if not opened with a shared context will be LOCKED until the process is terminated.

 

JUST REMEMBER THAT THREAD.ABORT IS EVIL!

 

The workaround to using thread.abort() is to use a stop variable on your thread and to then Join() the thread. Thread.Abort() should only be used in the case of a seemingly dead thread.

 

That said ... here's the code :) You will notice that,

  this._handleProtector = new FileStream.__FileStreamHandleProtector(ptr1, true);

Doesn't happen until well after the create file. During that time the only reference to the file handle is in a local variable. given an exception this information will be lost.

internal FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync, string msgPath, bool bFromProxy)
{
      IntPtr ptr1;
      this._fileName = msgPath;
      if (path == null)
      {
            throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path"));
      }
      if (path.Length == 0)
      {
            throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
      }
      if ((((mode < FileMode.CreateNew) || (mode > FileMode.Append)) || ((access < FileAccess.Read) || (access > FileAccess.ReadWrite))) || ((share < FileShare.None) || (share > FileShare.ReadWrite)))
      {
            string text1 = "mode";
            if ((access < FileAccess.Read) || (access > FileAccess.ReadWrite))
            {
                  text1 = "access";
            }
            if ((share < FileShare.None) || (share > FileShare.ReadWrite))
            {
                  text1 = "share";
            }
            throw new ArgumentOutOfRangeException(text1, Environment.GetResourceString("ArgumentOutOfRange_Enum"));
      }
      if (bufferSize <= 0)
      {
            throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
      }
      int num1 = (access == FileAccess.Read) ? -2147483648 : ((access == FileAccess.Write) ? 0x40000000 : -1073741824);
      string text2 = Path.GetFullPathInternal(path);
      this._fileName = text2;
      if (text2.StartsWith(@"\\.\"))
      {
            throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported"));
      }
      FileIOPermissionAccess access1 = FileIOPermissionAccess.NoAccess;
      if ((access & FileAccess.Read) != ((FileAccess) 0))
      {
            if (mode == FileMode.Append)
            {
                  throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode"));
            }
            access1 |= FileIOPermissionAccess.Read;
      }
      if ((access & FileAccess.Write) != ((FileAccess) 0))
      {
            if (mode == FileMode.Append)
            {
                  access1 |= FileIOPermissionAccess.Append;
            }
            else
            {
                  access1 |= FileIOPermissionAccess.Write;
            }
      }
      else if (((mode == FileMode.Truncate) || (mode == FileMode.CreateNew)) || ((mode == FileMode.Create) || (mode == FileMode.Append)))
      {
            throw new ArgumentException(string.Format(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo"), mode, access));
      }
      string[] textArray1 = new string[] { text2 } ;
      new FileIOPermission(access1, textArray1, false, false).Demand();
      bool flag1 = mode == FileMode.Append;
      if (mode == FileMode.Append)
      {
            mode = FileMode.OpenOrCreate;
      }
      Win32Native.SECURITY_ATTRIBUTES security_attributes1 = null;
      if ((share & FileShare.Inheritable) != FileShare.None)
      {
            security_attributes1 = new Win32Native.SECURITY_ATTRIBUTES();
            security_attributes1.nLength = Marshal.SizeOf(security_attributes1);
            security_attributes1.bInheritHandle = 1;
            share &= ((FileShare) (-17));
      }
      if (FileStream._canUseAsync && useAsync)
      {
            ptr1 = Win32Native.UnsafeCreateFile(text2, num1, share, security_attributes1, mode, 0x40000000, Win32Native.NULL);
            this._isAsync = true;
      }
      else
      {
            ptr1 = Win32Native.UnsafeCreateFile(text2, num1, share, security_attributes1, mode, 0x80, Win32Native.NULL);
            this._isAsync = false;
      }
      if (ptr1 != Win32Native.INVALID_HANDLE_VALUE)
      {
            this._handleProtector = new FileStream.__FileStreamHandleProtector(ptr1, true);
      }
      else
      {
            int num2 = Marshal.GetLastWin32Error();
            if ((num2 == 3) && text2.Equals(Directory.InternalGetDirectoryRoot(text2)))
            {
                  num2 = 5;
            }
            bool flag2 = false;
            if (!bFromProxy)
            {
                  try
                  {
                        textArray1 = new string[] { this._fileName } ;
                        new FileIOPermission(FileIOPermissionAccess.PathDiscovery, textArray1, false, false).Demand();
                        flag2 = true;
                  }
                  catch (SecurityException)
                  {
                  }
            }
            if (flag2)
            {
                  __Error.WinIOError(num2, this._fileName);
            }
            else
            {
                  __Error.WinIOError(num2, msgPath);
            }
      }
      int num3 = Win32Native.GetFileType(ptr1);
      if (num3 != 1)
      {
            this._handleProtector.Close();
            throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles"));
      }
      if (this._isAsync)
      {
            bool flag3 = false;
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
            try
            {
                  flag3 = ThreadPool.BindHandle(ptr1);
            }
            finally
            {
                  CodeAccessPermission.RevertAssert();
            }
            if (!flag3)
            {
                  throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
            }
      }
      this._canRead = (access & FileAccess.Read) != ((FileAccess) 0);
      this._canWrite = (access & FileAccess.Write) != ((FileAccess) 0);
      this._canSeek = true;
      this._isPipe = false;
      this._pos = 0;
      this._bufferSize = bufferSize;
      this._readPos = 0;
      this._readLen = 0;
      this._writePos = 0;
      if (flag1)
      {
            this._appendStart = this.SeekCore((long) 0, SeekOrigin.End);
      }
      else
      {
            this._appendStart = -1;
      }
}
Posted on Friday, December 23, 2005 12:07 PM | Back to top


Comments on this post: Why I don't use thread.abort

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Greg Young | Powered by: GeeksWithBlogs.net