当 Windows XP 中 UI 线程冻结时 System.Timers.Timer 也会冻结

发布于 2024-09-15 03:39:05 字数 4037 浏览 2 评论 0原文

您好。

您很可能知道,当用户界面线程也冻结时,System.Windows.Forms.Timer 也会冻结其操作,这是因为它们在同一线程中运行。

这迫使我使用 System.Timers.Timer,如果用户界面冻结,Timer 会继续运行其通常的进程,就像什么都没发生一样。

我的应用程序与 IE 一起完成大量工作,并且有时 IE 在浏览带有错误 Javascript 代码的网站时会冻结。因此,这也会冻结我的应用程序用户界面以及所有应用程序,因为我的应用程序中的所有内容都在同一线程上运行。为了解决这个问题,我的应用程序时不时地对 IE 进程运行一个简单的检查,看看它们是否仍在响应,如果不响应,它们就会被终止,所有这些都在另一个线程上进行。

此反作用在 Windows 7 32 位上运行完美,但是当我在 Windows XP 计算机上运行我的应用程序时,反作用没有效果,可能是因为当用户界面冻结时我的 System.Timers.Timer 也会冻结。一旦在另一个线程上执行,就不会发生这种情况,就像在 Windows 7 上不会发生一样。

这是对抗过程的代码

private System.Timers.Timer IEResponsiveCheckTimer = new System.Timers.Timer();

private void onLoad(object sender, EventArgs e)
{
    this.IEResponsiveCheckTimer.Interval = 15000;
    this.IEResponsiveCheckTimer.Elapsed += new System.Timers.ElapsedEventHandler(IEResponsiveCheck);
    this.IEResponsiveCheckTimer.Start();
}

private void IEResponsiveCheck(object sender, EventArgs e)
{
    Thread t = new Thread(new ThreadStart(IEResponsiveChecker));
    t.Start();
}

static void IEResponsiveChecker()
{
    bool terminate = false;
    foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
    {
        if (exe.ProcessName.StartsWith("iexplore"))
        {
            if (exe.Responding == false)
            {
                terminate = true;
                break;
            }
        }
    }
    if (terminate == true)
    {
        foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
        {
            if (exe.ProcessName.StartsWith("iexplore"))
                try { exe.Kill(); }
                catch { }
        }
    }
}

此代码非常简单。我们有一个 Timers.Timer 每 15 秒运行一次,一旦时间过去,就会执行一个方法,该方法依次运行 静态方法delegate在另一个 Thread 上,如果 IE 没有响应,该线程负责终止 IE。

我怎样才能让这段代码在 Windows XP 上运行良好,就像在 Windows 7 上运行一样。

感谢任何帮助。

谢谢。

编辑:

我还尝试了System.Threading.Timer相同的结果,在Windows 7中有效,但在Windows XP中无效。

编辑:遵循凯文·盖尔的建议:

我尝试仅使用线程来运行我的反作用,但我发现并不是线程本身不起作用。 Process.Responding 属性在 Windows XP 中无法正常工作。

新代码

private void onLoad(object sender, EventArgs e)
{
    Thread t = new Thread(new ThreadStart(IEResponsiveChecker));
    t.Start();
}

static void IEResponsiveChecker()
{
    bool terminate = false;
    foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
    {
        if (exe.ProcessName.StartsWith("iexplore"))
        {
            if (exe.Responding == false)
            {
                terminate = true;
                break;
            }
        }
    }
    if (terminate == true)
    {
        foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
        {
            if (exe.ProcessName.StartsWith("iexplore"))
                try { exe.Kill(); }
                catch { }
        }
    }
    Thread.Sleep(15000);
    IEResponsiveChecker();
}

这样,线程在 Windows 7 和 XP 上每 15 秒执行一次。但我认为它不起作用的原因是因为他在 IE 无响应时没有关闭 IE。

我发现他没有关闭 IE,因为根据 exe.Responding 来解析进程是否响应,在 Windows 7 中他检测到 IE 没有响应,而在 Windows XP 中则检测到 IE 没有响应。说 IE 正在响应,但事实上它没有响应。这就是为什么在 XP 中线程没有关闭 IE,所以我认为线程不起作用。

所以毕竟。问题是,在不使用 Process.Responding 属性的情况下,如何确定进程 iexplore.exe 是否实际响应?

Info:属性Process.Responding为了知道进程是否正在响应,需要Process.MainWindowHandle属性,由于某种原因,该属性根据此代码示例,在 Windows 7 中属性存在,但在 Windows XP 中不存在,因此 Process.Responding 在 XP 上也不起作用。有人知道解决方法吗?

后果:考虑到我的问题本身已经得到解答,我将奖励那些真正帮助我找到真正问题所在的人。该问题的问题继续此处

谢谢大家。

Hello.

You most likely are aware that a System.Windows.Forms.Timer freezes its action when the user interface thread also freezes, that happens because they run in the same thread.

That forced me to use a System.Timers.Timer which in turn if the user interface freezes the Timer continues to run its usual process like nothing ever happen.

Well my application does a allot of work with IE, and from time to time IE freezes when browsing a website with bad Javascript code. In consequence that also freezes my application user interface along with all the application, because everything in my application runs on the same Thread. To counteract that problem, my application from time to time runs a simple check on IE process's to see if they are still responding and if they don't they are terminated, all that on another Thread.

This counteraction runs perfect on Windows 7 32 bits, however when i run my application on a Windows XP machine that counteraction has no effect, maybe because my System.Timers.Timer also freezes when the user interface freezes. Which it shouldn't happen once its executed on another Thread like it doesn't happen on Windows 7.

Here is the code for the counteraction process

private System.Timers.Timer IEResponsiveCheckTimer = new System.Timers.Timer();

private void onLoad(object sender, EventArgs e)
{
    this.IEResponsiveCheckTimer.Interval = 15000;
    this.IEResponsiveCheckTimer.Elapsed += new System.Timers.ElapsedEventHandler(IEResponsiveCheck);
    this.IEResponsiveCheckTimer.Start();
}

private void IEResponsiveCheck(object sender, EventArgs e)
{
    Thread t = new Thread(new ThreadStart(IEResponsiveChecker));
    t.Start();
}

static void IEResponsiveChecker()
{
    bool terminate = false;
    foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
    {
        if (exe.ProcessName.StartsWith("iexplore"))
        {
            if (exe.Responding == false)
            {
                terminate = true;
                break;
            }
        }
    }
    if (terminate == true)
    {
        foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
        {
            if (exe.ProcessName.StartsWith("iexplore"))
                try { exe.Kill(); }
                catch { }
        }
    }
}

This code is pretty simple. We have a Timers.Timer running every 15 seconds, once its time elapses a method is executed which in turn runs the delegate of a static method on another Thread which is responsible to terminate IE if he isn't responding.

How can i get this code to run well on Windows XP like it runs on Windows 7.

Any help is appreciated.

Thanks.

EDIT:

I also tried a System.Threading.Timer same result, in Windows 7 works but not in Windows XP.

EDIT: Following Kevin Gale advice:

I've attempted using only the Thread to run my counteraction, and i have found that it isn't the Thread it self that isn't working. Its the Process.Responding property that isn't working well in Windows XP.

New Code:

private void onLoad(object sender, EventArgs e)
{
    Thread t = new Thread(new ThreadStart(IEResponsiveChecker));
    t.Start();
}

static void IEResponsiveChecker()
{
    bool terminate = false;
    foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
    {
        if (exe.ProcessName.StartsWith("iexplore"))
        {
            if (exe.Responding == false)
            {
                terminate = true;
                break;
            }
        }
    }
    if (terminate == true)
    {
        foreach (System.Diagnostics.Process exe in System.Diagnostics.Process.GetProcesses())
        {
            if (exe.ProcessName.StartsWith("iexplore"))
                try { exe.Kill(); }
                catch { }
        }
    }
    Thread.Sleep(15000);
    IEResponsiveChecker();
}

This way the Thread is executed every 15 seconds on both Windows 7 and XP. But the reason i thought it wasn't working, was because he didn't close IE when it was unresponsive.

And I've found he didn't closed IE because according to exe.Responding which resolves if the process is responding or not, in Windows 7 he detects that IE isn't responding and in Windows XP it say that IE is responding although in fact it isn't. Thats why in XP the Thread didn't closed IE, and there so i thought the Thread didn't work.

So after all. The problem is how can i find if the process iexplore.exe is actually responding or not without using the Process.Responding property?

Info: The property Process.Responding in order to know if the process is responding requires the Process.MainWindowHandle property, which for some reason according to this code sample, in Windows 7 that property exists but not in Windows XP, there so Process.Responding also doesn't work on XP. Anybody knows a workaround?

Aftermath: Considering that my question it self has been answered, i will award the one responsible to truly helping me finding what was really the problem. The question for that problem continues here.

Thanks everyone.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅唱ヾ落雨殇 2024-09-22 03:39:05

为什么要使用计时器。只需启动第二个线程并让它每 15 秒检查一次即可。这会更简单并且开销更低。

但如果你想保留计时器,也许 System.Threading.Timer 类可以解决这个问题。

Why use a timer at all. Just start the second thread and have it check every 15 seconds. That would be simpler and lower overhead.

But if you want to keep the timer maybe the System.Threading.Timer class might get around the problem.

虐人心 2024-09-22 03:39:05

Windows 7 在处理系统资源的线程安全方面做出了一些重大更改(例如从 SQL 中的表锁定改为行锁定)。您可能会看到对某些系统资源的争用,这些资源在 XP 中被阻止,但在 Win7 中允许多次访问。鉴于此,计时器在哪个线程上运行并不重要,因为所有线程都将在同一资源上阻塞。

也许如果您检测到您的应用程序中发生了这种情况,您可能会弹出一条消息,建议用户升级其操作系统。 :)

Windows 7 made some major changes in thread safety for handling of system resources (like going from table locking to row locking in SQL). You're probably seeing contention for some system resource that blocks in XP but allows multiple accesses in Win7. Given that, it's not going to matter what thread your timer is running on because all of the threads will block on the same resource.

Maybe if you detect that this has happened in your app you could pop up a message suggesting the user upgrade their OS. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文