C# 启动计时器会在应用程序启动时间歇性死锁

C# 启动计时器会在应用程序启动时间歇性死锁,c#,multithreading,winforms,timer,C#,Multithreading,Winforms,Timer,我有一个具有两个独立GUI线程的应用程序,主窗体在每个线程上运行。(这是为了允许不同屏幕上同时出现独立用户。) 每个窗口都有一个InactivityTimer组件,用于在用户处于非活动状态一段时间后将其带回主页 主要功能的相关部分: static void Main() { MainWindow form1 = new MainWindow(true); //check that we have a second screen if (S

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

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

主要功能的相关部分:

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);
    }
无活性体:

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

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

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

我已经深入研究了一段时间,但一无所获。更糟糕的是,我似乎无法在精简的应用程序中复制该问题。但我无法想象任何东西会妨碍计时器在停止后自动启动,工作正常


如果有人能找出这里发生的事情和/或找到它的修复方法,那就太棒了。

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

rory.ap的评论是正确的,只有锁等东西才会导致这样的死锁。然而,当我查看我的代码时,它从来没有点击过
Invoke
的行为就像这样一个构造(wrt UI线程),所以我没有注意到这些


然而今天我的注意力被吸引到了它上面,我发现在一个锁里面有一个
Invoke
,这导致了一个死锁。

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