WaitHandle以某种方式关闭

时间:2014-09-05 10:26:19

标签: c# .net multithreading winforms crash

我们有一个庞大且非常复杂的C#应用​​程序,有时(很少)从包含以下内容的用户发回崩溃报告:

The handle is invalid
   <stacktrace>
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.Threading.EventWaitHandle.Set()
   at System.Windows.Forms.Control.ThreadMethodEntry.Complete()
   at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
   at System.Windows.Forms.Control.WndProc(Message&amp; m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   </stacktrace>

使用IlSpy我检查了框架代码,似乎异常必须来自此处(在Control.InvokeMarshaledCallback中):

    try
    {
        if (NativeWindow.WndProcShouldBeDebuggable && !threadMethodEntry.synchronous)
        {
            this.InvokeMarshaledCallback(threadMethodEntry);
        }
        else
        {
            try
            {
                this.InvokeMarshaledCallback(threadMethodEntry);
            }
            catch (Exception ex)
            {
                threadMethodEntry.exception = ex.GetBaseException();
            }
        }
    }
    finally
    {
        threadMethodEntry.Complete(); // <-- here! This calls Set() on the wait handle
        if (!NativeWindow.WndProcShouldBeDebuggable && threadMethodEntry.exception != null && !threadMethodEntry.synchronous)
        {
            Application.OnThreadException(threadMethodEntry.exception);
        }
    }
}

然后我创建了一个测试程序,看看我是否可以复制这种情况,果然,这个测试可以做到:

    using System;
    using System.Windows.Forms;

    namespace Test
    {
        static class Program
        {
            [STAThread]
            static void Main()
            {
                AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }

            static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                var ex = (Exception)e.ExceptionObject;
                MessageBox.Show(ex.Message);
                MessageBox.Show(ex.StackTrace);
            }
        }
    }


using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Test
{
    public partial class Form1 : Form
    {
        [DllImport("kernel32.dll", SetLastError = true, PreserveSig = true)]
        static extern bool CloseHandle(
            [In] IntPtr handle);

        public Form1()
        {
            InitializeComponent();
        }

        void Post()
        {
            Text = "Some async method";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IAsyncResult wait = this.BeginInvoke((Action)Post);

            // Close the wait handle. When Post() returns the framework
            // tries to call .Set() on the wait event, but we closed it!
            IntPtr nativehandle = wait.AsyncWaitHandle.SafeWaitHandle.DangerousGetHandle();
            CloseHandle(nativehandle);
        }
    }
}

奖励信息:我只能得到句柄无效&#39;通过使用DangerousGetHandle()和p / invoke关闭本机句柄。调用AsyncWaitHandle.Close()生成&#39;安全句柄已关闭。

现在,问题是搜索我们的代码库,我找不到AsyncWaitHandle的单个实例。有大量的BeginInvoke,但没有等待,可能会意外关闭本机句柄。除非有其他办法,否则我错过了。

所以问题是:

什么可能导致这个原生句柄被关闭?

我应该注意一些框架竞争条件吗?似乎只有在多个线程同时发生许多事情时才会发生。

0 个答案:

没有答案