【问题标题】:Starting a Timer Intermittently Deadlocks at Application Startup [closed]在应用程序启动时启动计时器间歇性死锁[关闭]
【发布时间】:2016-09-28 22:49:50
【问题描述】:

我有一个具有两个独立 GUI 线程的应用程序,主窗体在每个线程上运行。 (这是为了允许不同屏幕上的同时独立用户。)

每个窗口都有一个 InactivityTimer 组件,用于在用户处于非活动状态一段时间后将其带回主页。

main函数的相关部分:

static void Main()
    {
        MainWindow form1 = new MainWindow(true);

        //check that we have a second screen
        if (Screen.AllScreens.Length > 1)
        {   //Setup the second screen on its own thread and bind events between the two
            System.Threading.Thread thread = new System.Threading.Thread(() =>
            {
                MainWindow form2 = new MainWindow(false);
                form2.FormClosed += (o, e) =>
                {
                    form1.Invoke((MethodInvoker)delegate
                    {
                        form1.Close();//close form1 when form2 closes. we dont need vice-versa because form2 is on a background thread.
                    });
                };

                /* Logic that binds events between the two forms*/

                Application.Run(form2);
            })
            { IsBackground = true };
            thread.Start();
        }
        Application.Run(form1);
    }

InactivityTimer:

public partial class InactivityTimer : System.Windows.Forms.Timer, IMessageFilter
{
    public InactivityTimer()
    {
        Initialise();
    }

    public InactivityTimer(IContainer container)
    {
        Initialise();
        container.Add(this);
    }

    private void Initialise()
    {
        InitializeComponent();
        Application.AddMessageFilter(this);
    }              

    public void ResetTimer()
    {
        Stop();
        Start();
    }

    public bool PreFilterMessage(ref Message m)
    {
        bool watching = /*logic that determines whether this is a message we are watching for (mainly mouse actions)*/;
        if (watching)
        {
            ResetTimer();
        }
        return false;//do not stop the event being dispatched
    }   
}

当我启动应用程序时,其中一个屏幕总是先于另一个显示,这并不意外。但有时(并非总是)当我在另一个屏幕出现之前与该屏幕进行交互时,应用程序就会停止,就像死锁一样。第二个屏幕从不显示,第一个屏幕停止响应输入。

如果发生这种情况时我在调试模式下“全部中断”,则应用程序总是卡在 InactivityTimer 的 ResetTimer() 中的 Start(); 上。

我以前曾看到过类似的行为,我认为这是因为它有时在创建父控件的句柄之前就已启动,并且如果 IsHandleCreated 为 false,则通过不尝试启动计时器来“修复”该问题。 但是:
a)我什至不确定这不仅仅是修复时间的改变;
b) 在这种情况下,我相当肯定父句柄已经创建,因为窗口正在显示;
c) 同样的修复在这里没有奏效。

我已经对此进行了一段时间的研究,但一无所获。更糟糕的是,我似乎无法在精简的应用程序中复制该问题。但我无法想象有什么会妨碍计时器在停止后自行调用 start 工作正常。

如果有人能弄清楚这里发生了什么和/或找出解决方法,那将是惊人的。

【问题讨论】:

  • 您的应用程序中是否有您未在此处显示的同步机制,例如锁还是信号量?
  • 我在各个地方都在使用lock(/*lock object*/){} 块,但是这些都是小部分,并没有做很多事情,并且在应用程序的完全不相关的部分中使用了不同的锁对象。在最坏的情况下,我可能会遇到少量争用,但不会出现死锁。
  • 只有这些会导致死锁。如果我们有机会帮助您解决问题,您需要向我们展示所有相关代码。
  • 但是我的任何锁怎么可能调用Start()(直接从windows库继承)阻塞?
  • 我不确定。你能把它归结为MCVE吗?

标签: c# multithreading winforms timer


【解决方案1】:

我今天才幸运地弄清楚发生了什么,因为调试器突然停在一个完全不同的地方。

rory.ap 在 cmets 中是正确的,只有像锁之类的东西才会导致这样的死锁。然而,当我查看我的代码时,它只是从未点击过 Invoke 就像这样一个构造(在 UI 线程中),所以我没有注意这些。

但是今天我的注意力被它吸引了,而且我在lock 中有一个Invoke,这导致了死锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多