OJ系统判题思路与代码实现
程序员文章站
2022-06-17 09:39:08
...
OJ系统判题思路与代码实现
毕业设计做了个OJ系统,做得不好,打算重做,因为比较感兴趣,涉及到了许多东西,做系统的同时又把我在学校里学的东西给捡了回来,哈哈。
一些相关说明:
- 主进程:调控子进程的程序。
- 子进程:执行源程序。
- 管道:(有名管道)子进程输出数据到管道中,主进程得以读取,半双工式环形缓冲区,半双工地读写决定了父/子只能有一个进程读/写,所以父子进程轮流阻塞。(听说,有名管道环形缓冲,待验证,待审查对程序影响力)。
- fork()创建子进程,复制一份父进程资源,然后创建子进程。这就造成了,两个进程执行同一份代码,通过判断pid值可知是父进程还是子进程。
- exec系列函数可执行源程序。子进程中调用exec系列函数,exec之后的代码不会被执行。
- setProcessLimit()自定义的,设定子进程资源限制,的函数,setrlimit()才是库函数(有问题,找男人)
- 捕获Linux进程信号量(略)
- 获取进程PCB控制块信息(运行时间,内存...), wait4(...)函数,PCB进程信息存在于调用wait4(...)函数传如的某个结构体引用中。 系统库结构体:struct rusage ru; (运行时间)runTime = ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000 + ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000; (运行内存)runMemory = ru.ru_maxrss;
- 外部输入: timeLimit:时间限制, memoryLimit: 内存限制, codeType: 代码类型, test.in:标准输入文件, test.out:标准输出文件
- 内部输出: exitValue: 进程退出值, judgeResult: 评测结果, runTime: 运行时间, runMemory: 运行内存
人为规定,子进程返回0表示正常结束。
/*
工作空间默认为根目录:/
1.工作空间内存在test.in作为输入数据
2.工作空间内存在test.out作为输出数据
3.工作空间内存在Main作为待运行程序
4.执行:./runCode 2 500 c/c++
(第一个参数:2代表时间时限2s,第二个参数:500代表空间限制500MB, 第三个参数是代码类型)
5.将会输出的格式:
result:AC
message:%s(可能存在)
runTime:%d
runMemory:%ld
*/
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <map>
#define FIFO "stdout_fifo"
typedef long long ll;
typedef void(*func)();
using namespace std;
string Signal[][2] = {{"RE", ""}, {"RE", " "}, {"RE", ""}, {"RE", ""},{"RE", "非法指令"},
{"RE", ""}, {"RE", "异常中止"}, {"RE", ""}, {"RE", "浮点运算溢出"},{"RE", ""},
{"RE", ""}, {"RE", "非法内存地址引用"}, {"RE", ""}, {"RE", ""},{"RE", ""},
{"RE", ""}, {"RE", "栈错误"}, {"RE", ""}, {"RE", ""},{"RE", ""},
{"RE", ""}, {"RE", ""}, {"RE", ""}, {"RE", ""},{"TL", "时间超限"},
{"RE", ""}, {"TL", ""}, {"RE", ""}, {"RE", ""},{"RE", ""},
{"RE", ""}};
void setProcessLimit(int timeLimit, ll memoryLimit);
void runC_cppCode();
void runJavaCode();
void init();
map<string, func> Map;
int main(int argc, char *args[]) {
chdir("/");
init();
int timeLimit = atoi(args[1]);
long memoryLimit = atol(args[2]);
memoryLimit <<= 10;
unlink(FIFO);
int res = mkfifo(FIFO, 0777);
pid_t pid = fork();
if(pid == 0) {
freopen("test.in", "r", stdin);
freopen("test.error", "w", stderr);
int fd = open(FIFO, O_WRONLY);
dup2(fd, 1);
setProcessLimit(timeLimit, memoryLimit);
Map[args[3]]();
} else {
FILE *output = fopen("test.out", "r");
char buf[BUFSIZ], buf2[BUFSIZ];
int fd = open(FIFO, O_RDONLY);
int len = 0;
int accept = 1;
while((len = read(fd, buf, BUFSIZ)) != 0) {
int len2 = fread(buf2, sizeof(char), len, output);
if(len != len2) {
accept = 0;
break;
} else {
for(int i = 0; i < len; i++) {
if(buf[i] ^ buf2[i]) {
accept = 0;
break;
}
}
if(accept == 0) {
break;
}
}
}
if(!(feof(output))) {
fgetc(output);
}
accept?(accept=feof(output)): kill(pid, SIGKILL);
fclose(output);
int status, runTime;
long runMemory;
struct rusage ru;
wait4(pid, &status, WUNTRACED, &ru);
runTime = ru.ru_utime.tv_sec * 1000
+ ru.ru_utime.tv_usec / 1000
+ ru.ru_stime.tv_sec * 1000
+ ru.ru_stime.tv_usec / 1000;
runMemory = ru.ru_maxrss;
if(accept == 0) {
cout << "result:WA\n" <<endl;
} else {
if(WIFEXITED(status)) {
cout << "result:" << (accept? (runMemory <= memoryLimit? "AC": "ML"): "WA") << endl;
} else {
int status2 = WIFSIGNALED(status)? WTERMSIG(status): (WIFSTOPPED(status)? WSTOPSIG(status): 0);
if(status2 == SIGSEGV && runMemory > memoryLimit) {
cout << "result:ML" << endl;
} else {
cout << "result:" << Signal[status2][0] << endl;
cout << "message:" << Signal[status2][1] << endl;
}
}
}
cout << "runTime:" << runTime <<endl;
cout << "runMemory:" << runMemory <<endl;
}
return 0;
}
void setProcessLimit(int timeLimit, ll memoryLimit) {
struct rlimit rl;
rl.rlim_cur = timeLimit;
rl.rlim_max = timeLimit + 1;
setrlimit(RLIMIT_CPU, &rl);
rl.rlim_cur = (memoryLimit + (memoryLimit >> 1)) << 10;
rl.rlim_max = (memoryLimit << 1) << 10;
setrlimit(RLIMIT_DATA, &rl);
}
void runC_cppCode() {
if(access("Main", F_OK) == -1) {
cerr << "Main没有找到" <<endl;
} else {
char *args[] = {NULL};
execv("Main", args);
}
}
void runJavaCode() {
if(access("Main.class", F_OK) == -1) {
cerr << "Main.class没有找到" <<endl;
} else {
char *args[] = {"java", "Main", NULL};
execvp("java", args);
}
}
void init() {
Map["c"] = runC_cppCode;
Map["c/c++"] = runC_cppCode;
Map["java"] = runJavaCode;
}
上一篇: Qt官方示例-图表主题
下一篇: Qt官方示例-Http