Python信号处理程序流与文件资源跨平台问题问询
问题分析与解答
示例代码
import os import signal import time class mre: def __init__(self) -> None: self.fd = None def write_file(self): with open("mre.log","w") as f: self.fd = f print("writing to file") while True: time.sleep(0.1) f.write("hello") def signal_handler(self, sig, frame): #delete the file try: #self.fd.close() os.remove("mre.log") print("file closed") except Exception as err: print("exception raised") raise err def main(self): signal.signal(signal.SIGINT, self.signal_handler) self.write_file() if __name__ == "__main__": temp = mre() temp.main()
问题1:Linux下程序执行流程解析
现象
在Linux系统运行程序,按下Ctrl+C时,signal_handler()被调用,文件被删除,但需要再次按下Ctrl+C程序才会终止。相关输出:
(yt) LAPTOP-28TNND21% echo $0 /usr/bin/zsh (yt) LAPTOP-28TNND21% python --version Python 3.8.10 (yt) LAPTOP-28TNND21% python mre.py writing to file ^Cfile closed ^Cexception raised Traceback (most recent call last): File "mre.py", line 34, in <module> temp.main() File "mre.py", line 30, in main self.write_file() File "mre.py", line 15, in write_file time.sleep(0.1) File "mre.py", line 26, in signal_handler raise err File "mre.py", line 22, in signal_handler os.remove("mre.log") FileNotFoundError: [Errno 2] No such file or directory: 'mre.log'
注释os.remove("mre.log")后,每次按Ctrl+C都会触发signal_handler,但程序陷入无限循环,需强制杀死进程才能终止:
(yt) LAPTOP-28TNND21% echo $0 /usr/bin/zsh (yt) LAPTOP-28TNND21% python --version Python 3.8.10 (yt) LAPTOP-28TNND21% python mre.py writing to file ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed ^Cfile closed
执行流程解析
- 程序启动后,
main()方法注册SIGINT信号(对应Ctrl+C)的处理函数signal_handler,随后调用write_file()。 write_file()进入with代码块,打开mre.log文件,进入无限循环:每隔0.1秒向文件写入一次"hello",此时程序持续阻塞在time.sleep(0.1)或f.write()操作中。- 第一次按下
Ctrl+C,操作系统触发SIGINT信号,Python暂停当前执行的代码,转去执行signal_handler:- 此时
with代码块未退出,文件句柄f仍持有文件,但Linux允许删除被进程打开的文件(文件会被标记为删除,直到所有打开它的句柄关闭后才会真正从磁盘移除),因此os.remove执行成功,打印"file closed"。 - 信号处理函数执行完成后,Python回到之前暂停的代码位置,继续执行无限循环,程序不会终止。
- 此时
- 第二次按下
Ctrl+C,再次触发signal_handler,此时文件已被删除,os.remove抛出FileNotFoundError,代码捕获异常后重新抛出,中断原来的无限循环,导致程序终止并打印栈追踪信息。 - 注释
os.remove后,每次signal_handler执行都不会抛出异常,执行完毕后程序回到无限循环继续运行,因此每次按Ctrl+C只会打印"file closed",但程序不会终止,必须用强制终止信号(如kill -9)才能结束进程。
问题2:Windows下文件被占用的原因
现象
在Windows系统运行程序,按下Ctrl+C后直接抛出权限错误,提示文件被占用:
(venv) PS D:\Downloads\testing-main\src> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 5 1 22621 436 (venv) PS D:\Downloads\testing-main\src> python --version Python 3.9.1 (venv) PS D:\Downloads\testing-main\src> python mre.py writing to file exception raised Traceback (most recent call last): File "D:\Downloads\testing-main\src\mre.py", line 34, in <module> temp.main() File "D:\Downloads\testing-main\src\mre.py", line 30, in main self.write_file() File "D:\Downloads\testing-main\src\mre.py", line 15, in write_file time.sleep(0.1) File "D:\Downloads\testing-main\src\mre.py", line 26, in signal_handler raise err File "D:\Downloads\testing-main\src\mre.py", line 22, in signal_handler os.remove("mre.log") PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'mre.log'
原因解析
你的假设完全正确:信号处理函数执行时,with代码块并没有退出,文件也没有被关闭。
- Windows文件系统机制与Linux不同:不允许删除正在被进程打开的文件,只要文件句柄还处于打开状态,
os.remove就会抛出权限错误。 - 当
Ctrl+C触发SIGINT信号时,Python暂停write_file里的无限循环(此时仍处于with代码块内部),转去执行signal_handler。此时文件句柄f仍然被with块持有,with块的退出清理逻辑只有在代码正常退出该块时才会触发,信号中断不会让with块提前执行关闭操作。 - 因此此时尝试删除文件,Windows会因为文件被当前进程打开而拒绝操作,抛出
PermissionError。这个异常被signal_handler捕获后重新抛出,最终中断程序的无限循环,导致程序终止。
内容的提问来源于stack exchange,提问作者GreninjaShuriken4
相关产品推荐
相关产品推荐

