Ubuntu下如何为GCC编译的C代码添加超时看门狗检测死循环?
给运行C程序的Python脚本添加看门狗超时机制
绝对没问题!既然不能修改C代码,咱们完全可以在Python层面给每个运行的C程序实例加上“超时看门狗”,一旦运行超过X分钟就判定为死循环(或长时间无响应)并给出提示。下面给你两种实用的实现方案:
方案一:用subprocess内置的超时参数(简单直接)
Python的subprocess模块自带timeout参数,能直接限制子进程的运行时间,超出后会抛出TimeoutExpired异常,咱们捕获这个异常就能判断程序可能陷入死循环了。
示例代码
import subprocess import os def run_c_program(c_source_path, input_file_path, timeout_minutes=5): # 先编译C代码(假设你的C程序读取标准输入) exe_path = c_source_path.replace(".c", ".out") compile_cmd = ["gcc", c_source_path, "-o", exe_path] try: subprocess.run(compile_cmd, check=True, capture_output=True, text=True) except subprocess.CalledProcessError as e: print(f"编译失败:{e.stderr}") return # 读取输入文件内容,传给C程序的标准输入 with open(input_file_path, "r") as f: input_data = f.read() # 运行C程序,设置超时时间(转换为秒) timeout_seconds = timeout_minutes * 60 try: result = subprocess.run( [exe_path], input=input_data, capture_output=True, text=True, timeout=timeout_seconds ) # 程序正常结束的处理逻辑 print(f"程序运行完成,返回码:{result.returncode}") # 可以在这里处理输出、日志等 except subprocess.TimeoutExpired: print(f"警告:程序运行超过{timeout_minutes}分钟,疑似陷入死循环!") # 可以强制终止子进程(不过subprocess超时后会自动终止) finally: # 清理编译后的可执行文件(可选) if os.path.exists(exe_path): os.remove(exe_path) # 调用示例:运行test.c,用input.txt作为输入,超时设为3分钟 run_c_program("test.c", "input.txt", timeout_minutes=3)
说明
- 这个方案的优势是代码简洁,无需额外依赖,适合大多数基础场景。
subprocess.TimeoutExpired触发时,Python会自动终止对应的C程序进程,不用担心残留进程。- 如果你的C程序是通过命令行参数接收输入而非标准输入,只需要调整
subprocess.run的参数列表即可。
方案二:用psutil实现更灵活的监控(含内存监控)
如果除了超时,你还想监控C程序的内存占用(毕竟你提到通过内存耗尽发现死循环),可以用psutil模块,它能实时跟踪进程的运行时间、内存、CPU使用率等指标,实现更精细化的看门狗。
步骤1:安装依赖
pip install psutil
示例代码
import subprocess import os import time import psutil def monitor_c_program(c_source_path, input_file_path, timeout_minutes=5, max_memory_mb=500): # 编译C代码 exe_path = c_source_path.replace(".c", ".out") compile_cmd = ["gcc", c_source_path, "-o", exe_path] try: subprocess.run(compile_cmd, check=True, capture_output=True, text=True) except subprocess.CalledProcessError as e: print(f"编译失败:{e.stderr}") return # 启动C程序,不阻塞,让它后台运行 with open(input_file_path, "r") as f: input_data = f.read() proc = subprocess.Popen( [exe_path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) proc.stdin.write(input_data) proc.stdin.close() # 开始监控 start_time = time.time() timeout_seconds = timeout_minutes * 60 is_timeout = False is_memory_exceeded = False while proc.poll() is None: # 进程还在运行 elapsed_time = time.time() - start_time # 检查超时 if elapsed_time > timeout_seconds: is_timeout = True break # 检查内存占用 try: process = psutil.Process(proc.pid) memory_info = process.memory_info() memory_used_mb = memory_info.rss / (1024 * 1024) # 转换为MB if memory_used_mb > max_memory_mb: is_memory_exceeded = True break except psutil.NoSuchProcess: # 进程已经意外终止 break # 每隔10秒检查一次,避免占用过多CPU time.sleep(10) # 根据监控结果处理 if is_timeout: print(f"警告:程序运行超过{timeout_minutes}分钟,疑似陷入死循环!") elif is_memory_exceeded: print(f"警告:程序内存占用超过{max_memory_mb}MB,疑似内存泄漏/死循环!") else: # 程序正常结束,处理输出 stdout, stderr = proc.communicate() print(f"程序运行完成,返回码:{proc.returncode}") if stdout: print(f"标准输出:{stdout}") if stderr: print(f"标准错误:{stderr}") # 确保进程被终止 if proc.poll() is None: proc.kill() proc.wait() # 清理可执行文件 if os.path.exists(exe_path): os.remove(exe_path) # 调用示例:超时5分钟,内存上限500MB monitor_c_program("test.c", "input.txt", timeout_minutes=5, max_memory_mb=500)
说明
- 这个方案不仅能监控超时,还能跟踪内存占用,完美匹配你提到的“内存耗尽”死循环场景。
- 通过
psutil.Process可以获取进程的更多指标,比如CPU使用率,你可以根据需求添加更多监控条件。 - 循环中加入
time.sleep(10)是为了避免Python进程频繁检查,节省系统资源,你可以根据需要调整间隔时间。
两种方案都不需要修改任何C代码,完全在Python层面实现看门狗逻辑,你可以根据自己的需求选择合适的一种。
内容的提问来源于stack exchange,提问作者Yoni Newman
相关产品推荐
相关产品推荐

