【问题标题】:Exception raised by Timer.Elapsed not caught by attempted global exception event handler Visual C#Timer.Elapsed 引发的异常未被尝试的全局异常事件处理程序捕获 Visual C#
【发布时间】:2017-08-06 16:29:21
【问题描述】:

已尽可能简化此问题以尝试隔离问题。我假设它与单独线程中引发的异常有关

让有一个 WindowsFormApp。

假设 Program 类源代码如下所示

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionOccurred);
        Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(UnhandledExceptionOccurred);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public static void UnhandledExceptionOccurred(object sender, UnhandledExceptionEventArgs e)
    {
        var x = (Exception)e.ExceptionObject;
        MessageBox.Show("Unhandled Exception\r\n" + x.Message);

    }

    public static void UnhandledExceptionOccurred(object sender, ThreadExceptionEventArgs e_thread)
    {
        var x = e_thread.Exception;
        MessageBox.Show("Thread Exception\r\n" + x.Message);
    }
}

对不起,如果这已经是压倒性的。让我尝试为这篇文章中发生的事情进行简化,以积累知识。

静态方法UnhandledExceptionOccurred() 有一个覆盖。这些方法用作未处理线程异常和来自主线程的未处理异常的事件处理程序。 (如果这不正确,我想对此进行更正,但这就是我的理解)。

假设在主窗体中,当单击按钮时抛出异常

private void button1_Click(object sender, EventArgs e)
{
    throw new Exception("Exception 1");
}

假设按钮被点击。异常在消息框读取时被很好地捕获

“线程异常异常1”

现在(几乎完成)假设在 Form1 的构造函数中,我创建了一个 System.Timers.Timer,其间隔为 5000 毫秒,并带有一个事件处理程序,用于处理引发异常的已用事件。

System.Timers.Timer T;
public Form1()
{
    InitializeComponent();
    T = new System.Timers.Timer();
    T.Interval = 5000; //Miliseconds;
    T.Elapsed += new ElapsedEventHandler(TimerElapsed);
    T.Start();
}

以及事件处理程序:

public void TimerElapsed(object sender, ElapsedEventArgs e)
{
    T.Stop();
    throw new Exception("Exception From Timer Elapsed");
}

现在假设表单已启动,经过了 5 秒。

没有出现消息框,也没有弹出 WindowsFormError 框。程序默默地吞下了异常,我可以单击前面提到的按钮并像以前一样出现一个消息框。

这是怎么回事?

我知道这可能与定时器的线程处理有关。我已经搜索和搜索,但还没有找到一种方法来访问计时器正在使用的线程的内部,以便我可以为其 UnhandledException 和 ThreadException 事件添加一些事件处理程序。

也许我可以使用System.Threading.Timers Timer

我注意到这种类型的计时器的构造函数采用CallbackMethod? (什么是回调方法?)也许这个回调方法可以用来将未处理的异常路由回MainUI线程?

感谢任何/所有输入。

【问题讨论】:

  • 这是System.Timers.Timer 的一个已知问题——计时器回调中任何未处理的异常都会被框架吞没。 始终System.Timers.Timer 回调中提供您自己的异常处理程序。或者,确实,不要使用System.Timers.Timer。如果您要使用System.Threading.Timer,请注意differences
  • 您是否有理由不为此使用System.Windows.Forms.Timer
  • 您还可以将当前计时器上的SynchronizingObject 设置为(也许)您的Form 对象。然后,这将在 UI 线程上调用回调,并且异常不会被吞没。
  • @lesscode 没有特别的原因。并且设置同步对象似乎已经解决了这个问题。谢谢

标签: c# multithreading exception timer visual-studio-2017


【解决方案1】:

将 System.Timers.Timer SyncronyzingObject 设置为主窗体可解决此问题。

System.Timers.Timer T;
public Form1()
{
    InitializeComponent();
    T = new System.Timers.Timer();
    T.SynchronizingObject = this;
    T.Interval = 5000; //Miliseconds;
    T.Elapsed += new ElapsedEventHandler(TimerElapsed);
    T.Start();
}

当 Elapsed 事件由可视 Windows 窗体组件处理时, 比如一个按钮,通过系统线程访问组件 pool 可能会导致异常或可能无法正常工作。避免这种情况 通过将 SynchronizingObject 设置为 Windows 窗体组件来产生效果, 这会导致调用处理 Elapsed 事件的方法 创建组件的同一线程。 -- Microsoft.Com

【讨论】:

    猜你喜欢
    • 2018-06-14
    • 2013-10-25
    • 1970-01-01
    • 2015-01-02
    • 2014-03-19
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多