在受控环境下运行应用程序的问题 (Win32)
Posted
技术标签:
【中文标题】在受控环境下运行应用程序的问题 (Win32)【英文标题】:Problems with running an application under controlled environment (Win32) 【发布时间】:2010-10-06 14:57:42 【问题描述】:我不确定如何标记这个问题或如何写标题,所以如果有人有更好的想法,请编辑它
优惠如下:
前段时间,我写了一个计算奥林匹克管理系统的小而关键的部分。系统的工作是获取参与者的提交(代码文件),编译它们,针对预定义的测试用例运行它们,并返回结果。加上你能想象到的所有其他事情。
我写的部分叫做Limiter。这是一个小程序,它的工作是获取另一个程序并在受控环境中运行它。在这种情况下,受控意味着对可用内存、计算时间和对系统资源的访问的限制。另外,如果程序崩溃,我应该能够确定异常的类型并将其报告给用户。此外,当进程终止时,应注意它执行了多长时间(分辨率至少为 0.01 秒,最好更多)。
当然,理想的解决方案是虚拟化,但我没有这么写的经验。
我对此的解决方案分为三个部分。
最简单的部分是访问系统资源。该程序将简单地使用有限的访问令牌执行。我结合了一些可用于所有进程的基本(所有人、匿名等)访问令牌,以便提供对系统的实际只读访问权限,但它正在执行的文件夹除外。
内存限制是通过作业对象完成的——它们允许指定最大内存限制。
最后,为了限制执行时间并捕获所有异常,我的 Limiter 作为调试器附加到进程。因此,我可以监控它花费的时间,如果花费的时间太长,我可以终止它。请注意,我不能为此使用 Job 对象,因为它们只报告作业的内核时间和用户时间。一个进程可能会执行类似Sleep(99999999)
的操作,这将不计入其中,但仍会禁用测试机器。因此,虽然我没有将进程的空闲时间计入其最终执行时间,但它仍然必须有一个限制。
现在,我不是这类低级事物的专家。我花了几天时间阅读 MSDN 并玩弄,并尽我所能想出了一个解决方案。不幸的是,它似乎没有像预期的那样运行。在大多数情况下,它似乎工作正常,但奇怪的情况不断出现。刚才我有一个小 C++ 程序,它自己在瞬间运行,但我的限制器报告了 8 秒的用户模式时间(取自作业计数器)。这是代码。它在大约半秒内打印输出,然后花费超过 7 秒的时间等待:
#include <iostream>
#include <vector>
using namespace std;
int main()
vector< vector<int> > dp(50000, vector<int>(4, -1));
cout << dp.size();
限制器的代码很长,所以我不在这里包含它。我也觉得我的方法可能有问题——也许我不应该做调试器的事情。也许有一些我不知道的常见陷阱。
我想要一些关于其他人如何解决这个问题的建议。也许已经有一些东西可以做到这一点,而我的限制器已经过时了?
补充:问题似乎出在我上面贴的那个小程序上。我已经为它开了一个new question,因为它有些无关。我仍然希望 cmets 采用这种方法来限制程序。
【问题讨论】:
您使用的是调试版本吗?这是否与附加的调试器一起运行?如果是这样,它是否看到任何异常? 不,这也发生在发布中。我设置了一些输出,这 8 秒没有花在 Listener 中。 为什么将监听器附加为调试器?将 Job 作为子进程生成并从父进程控制该进程不是更容易吗? 因为我想在它崩溃时捕获任何异常并向用户发送一个漂亮而彻底的崩溃信息。 【参考方案1】:在附加调试器的情况下运行可能会改变应用程序的特性。性能可能会受到影响,代码路径甚至会发生变化(如果目标进程基于调试器的存在执行操作,即IsDebuggerPresent
)。
我们使用的另一种方法是将我们自己的应用程序配置为作为 JIT 调试器运行。通过设置AeDebug
注册表项,您可以控制应用程序崩溃时调用的调试器。这样你只在目标进程崩溃时才介入,并且在正常运行时不会影响进程。
这个网站有一些关于设置事后调试器的细节:Configuring Automatic Debugging。
您限制内存、获取时间等的方法听起来都很好。
【讨论】:
不错。 :) 虽然从那以后我已经多次思考这个问题,每次都更加意识到这个任务是多么的无望。现代 PC 上程序的性能取决于很多外部因素,以至于我真的不知道如何进行公平的测量了。 :( @Vilx- 是的,PC 上的性能测量很糟糕,因为 Windows 有这么多的缓存层,几乎不可能获得可重现的场景(甚至微软内部也没有办法关闭它们)。查看这篇博文,我将在其中讨论一些可以帮助您进行性能测量的技巧:joshpoley.blogspot.com/2011/11/… 不仅仅是 Windows。硬件对你不利。就像 CPU 缓存一样:两个以列优先或行优先顺序遍历 2D 数组的程序将具有截然不同的性能,而在算法上它们是相同的。或公共总线:如果网络适配器突然决定要将数据负载转储到 RAM,CPU 需要等待(因为它们与 RAM 共享相同的总线)并且无能为力。抢先式多任务处理和虚拟内存使事情变得更糟,尽管我猜这些可以通过使用 DOS 来规避。以上是关于在受控环境下运行应用程序的问题 (Win32)的主要内容,如果未能解决你的问题,请参考以下文章
用VS2012或VS2013在win7下编写的程序在XP下运行就出现“不是有效的win32应用程序
Delphi:如何确定应用程序是不是在 Win32 / Win64 下运行并在 64 位上自动启动 64 位版本?
CreateProcess失败;代码193.%/不是有效的win32应用程序