Windows批处理接收Ctrl+C时向Python子进程发送SIGINT的方案问询
问题根源
你当前使用START /B启动的Python进程属于独立的后台进程,和运行批处理的主控制台进程不在同一个进程组,按下Ctrl+C时系统仅会将SIGINT信号发送给批处理主进程,不会同步转发给后台的Python子进程,因此你写的信号处理逻辑无法被触发。
解决方案1:修改原有批处理脚本
修改后的批处理会记录两个Python进程的PID,捕获Ctrl+C事件后调用系统接口向子进程发送CTRL_C_EVENT信号,触发你预设的信号处理逻辑:
@echo off setlocal enabledelayedexpansion :: 启动GNSS采集脚本并记录进程ID start "" /B "C:\Users\nisso\anaconda3\envs\sensor_logging\python.exe" "C:/Users/nisso/Desktop/sensor_logging/gnss_reader.py" set GNSS_PID=%! :: 启动IMU采集脚本并记录进程ID start "" /B "C:\Users\nisso\anaconda3\envs\sensor_logging\python.exe" "C:/Users/nisso/Desktop/sensor_logging/imu_reader.py" set IMU_PID=%! echo 采集程序已启动,GNSS PID: %GNSS_PID%, IMU PID: %IMU_PID% echo 按下Ctrl+C停止采集 :: 注册Ctrl+C退出处理逻辑 if not "%1"=="" goto on_exit :: 后台等待中断信号 :loop timeout /t 1 /nobreak >nul goto loop :on_exit echo 正在停止采集程序,请稍候... :: 调用PowerShell向子进程发送CTRL_C_EVENT信号 powershell -Command "$sig = Add-Type 'using System;using System.Runtime.InteropServices;public class Sig {[DllImport(\"kernel32.dll\")]public static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);[DllImport(\"kernel32.dll\")]public static extern bool AttachConsole(uint dwProcessId);[DllImport(\"kernel32.dll\")]public static extern bool FreeConsole();}' -PassThru; $sig::FreeConsole(); if ($sig::AttachConsole(%GNSS_PID%)) { $sig::GenerateConsoleCtrlEvent(0, 0); Start-Sleep -Milliseconds 500; $sig::FreeConsole(); }; if ($sig::AttachConsole(%IMU_PID%)) { $sig::GenerateConsoleCtrlEvent(0, 0); Start-Sleep -Milliseconds 500; $sig::FreeConsole(); }" :: 等待进程完成残留写入后退出 timeout /t 2 /nobreak >nul echo 采集已安全停止 exit /b 0
解决方案2:使用PowerShell启动(更简洁)
如果可以接受用PowerShell脚本替代批处理,逻辑更简单稳定,保存为start_collect.ps1运行即可:
# 启动两个采集进程并获取PID $gnssProc = Start-Process -FilePath "C:\Users\nisso\anaconda3\envs\sensor_logging\python.exe" -ArgumentList "C:/Users/nisso/Desktop/sensor_logging/gnss_reader.py" -NoNewWindow -PassThru $imuProc = Start-Process -FilePath "C:\Users\nisso\anaconda3\envs\sensor_logging\python.exe" -ArgumentList "C:/Users/nisso/Desktop/sensor_logging/imu_reader.py" -NoNewWindow -PassThru try { # 等待进程运行,捕获Ctrl+C中断 Wait-Process -Id $gnssProc.Id, $imuProc.Id -ErrorAction Stop } catch { Write-Host "正在停止采集程序,请稍候..." # 发送CTRL_C_EVENT信号 $sig = Add-Type 'using System;using System.Runtime.InteropServices;public class Sig {[DllImport("kernel32.dll")]public static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);[DllImport("kernel32.dll")]public static extern bool AttachConsole(uint dwProcessId);[DllImport("kernel32.dll")]public static extern bool FreeConsole();}' -PassThru $sig::FreeConsole() if ($sig::AttachConsole($gnssProc.Id)) { $sig::GenerateConsoleCtrlEvent(0, 0) Start-Sleep -Milliseconds 500 $sig::FreeConsole() } if ($sig::AttachConsole($imuProc.Id)) { $sig::GenerateConsoleCtrlEvent(0, 0) Start-Sleep -Milliseconds 500 $sig::FreeConsole() } # 等待进程完成写入后退出 Wait-Process -Id $gnssProc.Id, $imuProc.Id -Timeout 2 Write-Host "采集已安全停止" }
可选优化
建议在你的Python代码的写入逻辑后添加手动刷新缓存的代码,避免缓存中的数据未写入磁盘:
f.write(f"{t}\t{serialString}\n") f.flush()
内容的提问来源于stack exchange,提问作者Morten Nissov
相关产品推荐
相关产品推荐

