评测机需要什么呢?
- 基本的
AC
,WA
,RE
- 高级一点的
TLE
,MLE
- 更加先进的沙箱
- 超先进的
CTLE
,CMLE
- 更具有实用价值的
SPJ
,testlib
,交互器
以上全部实现的judger
大概掰着指头都可以数过来,LOJ
,UOJ
,Codeforces
, etc…
自己写评测机!
以下文字只适用于linux下
ulimit
可能出于多种原因,比如自己出题,20+组数据自己一个一个验非常繁琐,等等。
我和kZIme写了OALJ,由于刚开始写的时候,我和kZime都非常naive,写出来的是一个只能判断答案正确与否的东西。后来,我了解到了一条叫做ulimit
的命令,可以用来限制进程的最大运行时间/内存。
于是就通过py脚本执行这个操作,通过判断程序的返回值来确定运行状态,通过diff
来判断答案是否正确。
缺点就是无法获取内存的多少。
fork-exec
后来我又学习了一个,了解了linux的进程机制。
在此之前,首先说一下一个虚拟地址空间
虚拟地址空间
在早期的Windows中,常常会出现一个程序跑飞,把其他程序也干掉,顺手蓝屏的操作。或者是神仙打架,大家一起gg。出现这些情况的原因在于早期的Windows中,程序可以直接操作到物理内存,如果出现了越界等操作,有时甚至会跨越到别的程序的内存里去。为了解决这个问题,操作系统为应用程序提供了“全世界的内存都是我的”的假象,即虚拟地址空间。
在操作系统提供的抽象中,每个程序享有独占的内存空间(好棒的感觉),如果你瞎搞,就会立刻已Segment fault
崩溃掉,而不会去祸害他人。
fork
fork是一个系统函数,可以将当前进程“复制”一份一模一样的,不过奇妙的是,由于调用fork会出现两个一模一样的进程,新进程是旧进程的孩儿,fork会返回两次,一次是在调用方,返回新进程的pid,另一次是在新进程,返回0,以告诉它“你是旧进程的孩儿”。
注意fork调用后,新旧进程使用不同的虚拟地址空间,所以他们互不影响。
exec
exec也是一个系统函数,可以将当前进程替换成要执行的进程,以前进程的信息将被完全抹去(莫名中二)。
所以,说了这么多,有什么用呢?
我们可以在评测的时候将评测机自身fork一下,让新进程exec成待评测程序。
然后旧进程作为新进程的爸爸,自然可以为所欲为,监测内存啥的不在话下,如果超时/超内存就一个SIGKILL
甩他脸上。
嗯。。待续。。