我不确定如何标记此问题或如何撰写标题,所以如果有人有更好的想法,请编辑它
这是交易:
前段时间我曾写过一个小小但非常重要的计算奥林匹克管理系统。系统的工作是从参与者(代码文件)获取提交,编译它们,针对预定义的测试用例运行它们,并返回结果。加上你可以想象的其他所有东西。
我写的部分叫做 Limiter 。这是一个小程序,其工作是采取另一个程序并在受控环境中运行它。在这种情况下受控制意味着可用内存,计算时间和对系统资源的访问的限制。此外,如果程序崩溃,我应该能够确定异常的类型并将其报告给用户。此外,当流程终止时,应该注意它执行了多长时间(分辨率至少为0.01秒,更好)。
当然,对此的理想解决方案是虚拟化,但我没有那么有经验的写作。
我对此的解决方案分为三个部分。
最简单的部分是访问系统资源。该程序只需使用有限的访问权限执行即可。我结合了一些可用于所有进程的基本(Everyone,Anonymous等)访问令牌,以便实际上提供对系统的只读访问权限,但正在执行的文件夹除外。
内存限制是通过作业对象完成的 - 它们允许指定最大内存限制。
最后,为了限制执行时间并捕获所有异常,我的Limiter作为调试器附加到进程。因此,如果花费的时间太长,我可以监控它花费的时间并终止它。请注意,我不能使用Job对象,因为它们只报告作业的内核时间和用户时间。一个进程可能会执行类似Sleep(99999999)
的操作,这些操作不会计入其中,但仍会禁用测试计算机。因此,虽然我没有在最终执行时间内计算进程空闲时间,但它仍然必须有一个限制。
现在,我不是这类低级别的专家。我花了几天时间阅读MSDN并玩游戏,并尽可能地提出了解决方案。不幸的是,它似乎没有像预期的那样运行。在大多数情况下,它似乎工作正常,但奇怪的情况继续爬升。刚才我有一个小C ++程序,它可以在一瞬间运行,但我的Limiter报告8秒的用户模式时间(取自作业计数器)。这是代码。它打印输出大约半秒钟,然后花费超过7秒等待:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector< vector<int> > dp(50000, vector<int>(4, -1));
cout << dp.size();
}
限制器的代码非常冗长,所以我不在此处。我也觉得我的方法可能有问题 - 也许我不应该做调试器的东西。也许有一些我不知道的常见陷阱。
我想就其他人如何解决这个问题提出一些建议。也许已经有了这样的事情,我的Limiter已经过时了?
<小时/> 已添加:问题似乎出现在我上面发布的小程序中。我为它开了一个new question,因为它有点不相关。我仍然喜欢这种限制程序的方法的评论。
答案 0 :(得分:0)
使用附加的调试器运行可以更改应用程序的特征。性能可能会受到影响,代码路径甚至可能会发生变化(如果目标进程根据调试器的存在来执行操作,即IsDebuggerPresent
)。
我们使用的另一种方法是将我们自己的应用程序配置为作为JIT调试器运行。通过设置AeDebug
注册表项,您可以控制应用程序崩溃时调用的调试器。这样,只有在目标进程崩溃时才会跳转,并且在正常运行时它不会影响进程。
此网站提供了有关设置事后调试程序的一些详细信息:Configuring Automatic Debugging。
限制记忆,获取计时等的方法听起来都很完美。