我不完全确定如何标记这个问题或如何编写标题,所以如果有人有一个更好的主意,请编辑它
这是交易:
前一段时间,我写了一个计算奥林匹克pipe理系统的一个小小的但是非常重要的部分。 系统的工作是从参与者(代码文件)获得提交,编译它们,根据预定义的testing用例运行它们并返回结果。 加上所有其他的东西,你可以想象它应该做的。
我写的部分叫Limiter 。 这是一个小程序,其工作是采取另一个程序,并在受控环境中运行。 在这种情况下的控制意味着对可用内存的限制,计算时间和对系统资源的访问。 另外,如果程序崩溃,我应该能够确定exception的types并向用户报告。 另外,当进程终止时,应该注意执行了多长时间(分辨率至less为0.01秒,更好)。
当然,理想的解决scheme是虚拟化,但我没那么有经验。
我的解决scheme分为三个部分。
最简单的部分是对系统资源的访问。 该程序只需使用有限的访问令牌即可执行。 我将所有进程都可用的一些基本(Everyone,Anonymous等)访问令牌结合起来,以便为系统提供实际的只读访问权限,但执行文件夹除外。
内存的限制是通过作业对象完成的 – 它们允许指定最大内存限制。
最后,为了限制执行时间并捕获所有exception,我的Limiter作为一个debugging器附加到进程中。 因此,我可以监控花费的时间,如果花费太长时间,可以终止花费的时间。 请注意,我无法使用Job对象,因为他们只报告作业的内核时间和用户时间。 一个进程可能会做一些像Sleep(99999999)
这样的东西,它们都不算在内,但仍然会禁用testing机器。 因此,虽然在最后的执行时间里我没有计算进程的空闲时间,但它仍然有一个限制。
现在,我不是像这样的低级别的东西的专家。 我花了几天的时间阅读MSDN并玩弄,并尽可能提出了一个解决scheme。 不幸的是,它似乎没有运行得如预期的那样好。 大多数情况下,它似乎工作正常,但奇怪的情况下不断爬升。 刚才我有一个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(); }
限制器的代码很长,所以我不在这里包括它。 我也觉得我的方法可能有些问题 – 也许我不应该做debugging器的东西。 也许有一些我不知道的常见陷阱。
我想就其他人如何解决这个问题提供一些build议。 也许已经有这样做了,我的限制器已经过时了吗?
补充:这个问题似乎在我上面发布的小程序中。 我已经开了一个新的问题 ,因为它有点不相关。 我仍然喜欢这种限制程序的方法。
使用附加的调试器运行可以改变应用程序的特性。 性能可能会受到影响,并且代码路径甚至可能会改变(如果目标进程根据调试器的存在执行操作,即IsDebuggerPresent
)。
我们使用的另一种方法是将我们自己的应用程序配置为作为JIT调试器运行。 通过设置AeDebug
注册表项,您可以控制应用程序崩溃时调用哪个调试器。 这样,只有在目标进程崩溃时才跳入,并且在正常运行时不影响进程。
这个站点有一些关于设置事后调试器的细节: 配置自动调试 。
你的方法来限制内存,获得时间等所有听起来都很好。