在紧密循环中处理windows事件?

在紧密循环中处理windows事件?,windows,multithreading,winapi,cpu-usage,Windows,Multithreading,Winapi,Cpu Usage,我已经为一种脚本语言编写了一个编译器和解释器。解释器是一个DLL“引擎”,它在一个线程中运行,可以加载许多100或1000个已编译字节码应用程序,并将它们作为一组内部进程执行。有一个主循环,在将一个进程移动到下一个进程之前,从每个加载的应用程序进程中执行一些指令 编译后的应用程序中的字节码指令可以是低级指令pop、push、add、sub等,也可以是对外部函数库的调用,而外部函数库是完成大部分工作的地方。这些外部库可以回调引擎,使内部进程进入休眠状态,等待特定事件,外部函数可能在收到事件后再次唤

我已经为一种脚本语言编写了一个编译器和解释器。解释器是一个DLL“引擎”,它在一个线程中运行,可以加载许多100或1000个已编译字节码应用程序,并将它们作为一组内部进程执行。有一个主循环,在将一个进程移动到下一个进程之前,从每个加载的应用程序进程中执行一些指令

编译后的应用程序中的字节码指令可以是低级指令pop、push、add、sub等,也可以是对外部函数库的调用,而外部函数库是完成大部分工作的地方。这些外部库可以回调引擎,使内部进程进入休眠状态,等待特定事件,外部函数可能在收到事件后再次唤醒内部进程。如果所有的内部进程都处于睡眠状态,并且大多数时间都处于睡眠状态,那么我也可以将引擎置于睡眠状态,从而将CPU移交给其他线程

但是,没有什么可以阻止某人编写一个脚本,该脚本只执行如下紧密循环:

while1 x=1; 结束时

这意味着我的主循环将永远不会进入睡眠状态,因此CPU将上升到100%,并锁定系统。我希望我的引擎尽可能快地运行,同时仍能处理windows事件,以便其他应用程序在遇到类似于上述的紧密循环时仍能响应

因此,我的第一个问题是如何在主循环中添加代码,以确保在不降低主引擎速度的情况下处理windows事件,而主引擎应该以尽可能快的速度运行

另外,如果能够设置我的引擎可以使用的最大CPU使用量,并通过调用偶尔的Sleep1来降低CPU使用量,那就太好了

因此,我的第二个问题是,如何将CPU使用率降低到所需的水平

引擎是用Borland C++编写的,并调用Win32 API。 提前感谢

1。在运行脚本的同时运行消息循环 我想让我的引擎和我的一样快 可能的话,在处理的时候 windows事件,以便其他 应用程序在以下情况下仍然响应 类似于上述的紧密循环是 遇到

在执行另一个操作时继续运行消息循环的最佳方法是将另一个操作移动到另一个线程。换句话说,将脚本解释器移动到第二个线程,并从运行消息循环的主UI线程与其通信

当你说Borland C++时,我假设你使用C++ Builder?在这种情况下,主线程是唯一一个与UI交互的线程,其消息循环通过运行。如果您定期调用库回调,这是可重入的,可能会导致问题。不要这样做

对您的问题的一条评论建议将每个脚本实例移动到单独的线程。这将是理想的。但是,要注意脚本保持状态时调用的DLL的问题-DLL是按进程加载的,而不是按线程加载的,因此如果它们保持状态,您可能会遇到线程问题。目前,为了解决您当前的问题,我建议将所有脚本执行转移到一个单独的其他线程

您可以通过多种方式在线程之间进行通信,例如使用或在线程之间发布消息。因为您使用的是Borland C++,您应该有权访问VCL。它有一个很好的线程包装器类,名为。从中派生并将脚本循环置于执行状态。您可以使用阻塞等待或不阻塞;方法可以在目标线程处理其消息循环以在另一个线程的上下文中运行方法时随时运行

作为旁注:

那么另一个 应用程序在以下情况下仍然响应 类似于上述的紧密循环是 遇到

这很奇怪。在现代的、抢占式多任务的Windows版本中,即使您的程序非常繁忙,其他应用程序也应该能够响应。您是否在处理线程优先级方面做了一些奇怪的事情,或者您是否在使用大量内存以便调出其他应用程序

2.在脚本中处理无限循环 你写道:

没有什么可以阻止某人 写一个只做一个简单动作的脚本 像这样的紧密循环:

当x=1时;结束时

这意味着我的主循环永远不会 进入睡眠状态,CPU 上升到100%并锁定 系统

但如何处理这一问题的短语如下:

而且,如果能够 设置我的引擎的最大CPU使用率 可以使用和节流CPU 通过调用临时 睡觉1

所以我的第二个问题是,我怎样才能 将CPU使用率降到最低限度 要求的级别

我认为你采取了错误的方法。像while1 x=1的无限循环;endwhile是脚本中的一个bug,但它不应该是ta 关闭主机应用程序。仅仅限制CPU不会使应用程序能够处理这种情况。而且,使用大量CPU并不一定是个问题:如果CPU可以运行,那么就这样做吧!只使用一点计算机的CPU并没有什么神圣之处。毕竟它是用来使用的。我认为您真正想要的是,在运行此脚本时,能够通过第二个线程继续让应用程序能够响应,然后:

检测脚本何时“没有响应”,或何时没有调用回调

能够采取行动,例如询问用户是否要终止脚本

另一个这样做的程序是Firefox。如果您转到一个脚本行为不正常的页面,最终会出现一个对话框,询问您是否要停止脚本运行

如果不了解脚本的实际解释或运行方式,我无法对这两个问题给出详细的答案。但我可以提出一种方法,即:

您的解释器可能运行一个循环,获取下一条指令并执行它。当前,通过从正在执行的指令之一运行的回调来提供交互性。我建议通过让您的回调简单地记录它最后一次被调用的时间来利用它。然后,在处理线程中,每一条指令或每十条或一百条指令都会对照上一次回调时间检查当前时间。如果过了很长一段时间,比如说十五秒或三十秒,这可能表明脚本被卡住了。通知主线程,但继续处理

就时间而言,像这样的事情可能就足够了

下一步:您的主UI线程可以通过询问用户做什么来对此作出反应。如果要终止脚本,请与脚本线程通信以设置标志。在脚本处理循环中,再次检查每一条指令或每一百条指令是否有此标志,如果已设置,则停止

当您移动到每个脚本解释器有一个线程时,您可以使用TThread的终止标志。惯用的说法是,对于在线程中无限运行的东西,您只需运行一段时间!在Execute函数中终止&[任何其他条件]循环


要真正回答您关于使用更少CPU的问题,最好的方法可能是将线程的优先级using更改为较低的优先级,例如线程优先级低于正常值。如果没有其他需要运行的内容,它仍将运行。这将影响脚本的性能。另一种方法是按照您的建议使用,但这实际上是人为的。也许会稍微好一点——它让位于操作系统选择的另一个线程。就个人而言,我认为CPU是可以使用的,如果您解决了交互UI和处理失控脚本的问题,那么如果您的脚本需要,那么使用所有CPU应该没有问题。如果您使用了太多的CPU,也许可以优化解释器本身。您需要运行探查器,找出CPU时间花在哪里。

尽管设计糟糕的脚本可能会让您陷入无所事事的循环,但不要担心。Windows是为处理这类事情而设计的,它不会让您的程序占用超过其CPU的合理份额。如果它成功地获得了100%,那只是因为没有其他东西想要运行。

如果你正在制定一个协作多任务方案,而脚本不协作,那么你真的应该强制它吗?如果这是你想要的,那就制定一个先发制人的机制。我想你是在向windows 3.1倒退。您有一个完整的多进程和多线程操作系统。为什么不让每个脚本在自己的线程中运行并管理这些线程呢。操作系统将负责执行上下文切换,并为每个脚本分配处理器时间。然后,您可以控制线程优先级并管理线程生存期。对于如图所示的无限循环,您可以在引擎上采取一些步骤来终止有问题的线程,即使您不这样做,这也不会停止其他脚本的运行。Sean,您似乎对SO不熟悉:欢迎:上次发布答案已经有几天了。你应该向上投票你认为有用的答案,点击答案左上角数字上方的三角形,如果你的问题回答得很好,请将其标记为接受答案,然后单击勾号。我们在这里花了很多精力来回答问题,这是利他主义的,但是得到积分的“奖励”很好。谢谢你的全面回答。。我的解释器DLL在它自己的线程中运行,但是如果这个线程进入一个紧循环,它将锁定GUI前端并减慢整个机器的速度。我认为答案是通过Synchronise调用ProcessMessages,以确保windows事件仍在处理中。我没有在单独的线程中运行脚本有很多原因,其中一个原因是可能有1000多个脚本同时运行,我并不热衷于创建5000个操作系统线程……你可以 d创建几个脚本实例,并让每个线程运行几个脚本实例。ProcessMessages通常不是一个好主意,它可以重新进入。如果主线程没有做任何其他事情,它应该已经在处理消息了!