【发布时间】:2017-10-08 22:11:15
【问题描述】:
我是一个很长一段时间的读者,但这是我在这里的第一个问题。
我正在编写一个 Python 3 程序(我目前正在自学)来编译和运行一组应该做同样事情的 C++ 程序(学生提交的作业)并将它们的输出与预期的结果进行比较输出我已经在一个文本文件中。
我正在寻找一种方法来运行这些可执行文件,以使我能够:
- 如果可执行文件没有结束,则在某个时间限制(例如 10 秒)后终止它。
- 捕获可执行文件的所有输出(包括 stdout、stderr 和任何“shell”消息,如分段错误、内存/核心转储等)
- 即使可执行文件崩溃或被强制终止(超过允许的时间后),我也需要捕获到该点的“部分”输出。
- 屏幕上没有任何内容(没有输出或错误消息)。
到目前为止,我尝试过的所有事情(从类似问题的答案)都缺少一些东西。我找不到满足我所有需求的产品(以上几点)。 以下是一些示例:
check_output()(如在this 问题中)在可执行文件崩溃时不会收集输出,并且某些消息(如核心转储)仍会显示在屏幕上。 p>
Popen()(如this)似乎不会终止可执行文件(超过时间时)。 python 线程结束(我希望我在这里使用正确的术语),但可执行文件继续运行。
尽管不鼓励使用像 os.system() 这样的方法,但我还是尝试了它们,但它们并没有表现得更好。
如果有人能指出实现这一目标的方法,我将不胜感激。我为任何语法错误道歉,因为英语不是我的第一语言。如果需要任何进一步的细节,请告诉我。 谢谢,
编辑:
这是我的 python 代码的最小副本:
from subprocess import STDOUT, check_output, TimeoutExpired
timeLimit = 3 # seconds
strOutput = ''
try:
output = check_output('./a.out', stderr = STDOUT, timeout = timeLimit)
strOutput = ''.join(map(chr, output))
except TimeoutExpired as e:
strOutput += 'Error: Time limit exceeded, terminated..'
except Exception as e:
strOutput += 'Error: ' + str(e)
f = open('report.txt','w')
f.write(strOutput)
f.close()
我还包括一些 C++ 示例,其中包含一些错误,以创建用于测试先前代码的可执行文件。 它们都可以编译为:g++ programName.cpp
#include <iostream>
using namespace std;
int main()
{
cout << "This one is working correctly!" << endl;
}
以下代码会导致“除以零”错误。 check_output() 未捕获此错误之前打印的语句
#include <iostream>
using namespace std;
int main()
{
cout << "Trying to divide by zero.." << endl;
cout << 3 / 0 << endl;
}
此代码等待意外输入(应在指定超时后由脚本终止)
#include <iostream>
using namespace std;
int main()
{
int x;
cout << "Waiting for an unexpected input.." << endl;
cin >> x;
}
我找不到重现 核心转储 问题的可靠方法。核心转储是一个特殊情况问题,因为 check_output() 无法捕获其输出(它直接/仅进入屏幕)。
附:我无法添加标签“check_output()”,我没有足够的声誉。
【问题讨论】:
-
你使用的是什么操作系统?
-
我目前在我的 Linux Mint 18.1 笔记本电脑上运行,但该脚本旨在在学校的 Ubuntu 16.04 服务器上运行。
-
subprocess.call()和timeout在其异常处理程序中调用p.kill()和p.wait(),如果超时到期,则会调用该处理程序。因此,它确实实际上杀死了立即生成的进程。 -
现在,如果你生成的进程有孩子,杀死它可能不会杀死孩子——但如果这是你的问题,你应该提供一个 minimal reproducible example 让其他人复制它,作为最佳实践修复方法会因细节而异。在某些情况下,正确的解决方法可能是修改调用它的方式以展平进程树,从而完全避免拥有这些子进程。 (如果你有一个中间的 shell 脚本,拥有它
exec它产生的程序属于此类解决方案)。 -
感谢大家的回复。我编辑了问题以包含所需的代码部分。