python兼职平台信号处理_如何在Windows机器上处理python中的信号
Python的os.kill在Windows上包含了两个不相关的API.当sig参数为CTRL_C_EVENT或CTRL_BREAK_EVENT时,它会调用GenerateConsoleCtrlEvent.在这种情况下,pid参数是进程组ID.如果后一个调用失败,并且对于所有其他sig值,则调用OpenProcess然后调用TerminateProcess.在这种情况下,pid参数是进程ID,sig值作为退出代码传递.终止Windows进程类似于将SIGKILL发送到POSIX进程.通常应该避免这种情况,因为它不允许过程干净地退出.
请注意,os.kill的文档错误地声称“kill()还会使进程句柄被杀死”,这从来都不是真的.它调用OpenProcess来获取进程句柄.
对于跨平台代码,使用WinAPI CTRL_C_EVENT和CTRL_BREAK_EVENT而不是SIGINT和SIGBREAK的决定是不幸的.它还没有定义GenerateConsoleCtrlEvent在传递不是进程组ID的进程ID时所执行的操作.在采用进程ID的API中使用此函数充其量是可疑的,并且可能非常错误.
根据您的特殊需求,您可以编写一个适配器函数,使os.kill对于跨平台代码更加友好.例如:
import os
import sys
import time
import signal
if sys.platform != 'win32':
kill = os.kill
sleep = time.sleep
else:
# adapt the conflated API on Windows.
import threading
sigmap = {signal.SIGINT: signal.CTRL_C_EVENT,
signal.SIGBREAK: signal.CTRL_BREAK_EVENT}
def kill(pid, signum):
if signum in sigmap and pid == os.getpid():
# we don't know if the current process is a
# process group leader, so just broadcast
# to all processes attached to this console.
pid = 0
thread = threading.current_thread()
handler = signal.getsignal(signum)
# work around the synchronization problem when calling
# kill from the main thread.
if (signum in sigmap and
thread.name == 'MainThread' and
callable(handler) and
pid == 0):
event = threading.Event()
def handler_set_event(signum, frame):
event.set()
return handler(signum, frame)
signal.signal(signum, handler_set_event)
try:
os.kill(pid, sigmap[signum])
# busy wait because we can't block in the main
# thread, else the signal handler can't execute.
while not event.is_set():
pass
finally:
signal.signal(signum, handler)
else:
os.kill(pid, sigmap.get(signum, signum))
if sys.version_info[0] > 2:
sleep = time.sleep
else:
import errno
# If the signal handler doesn't raise an exception,
# time.sleep in Python 2 raises an EINTR IOError, but
# Python 3 just resumes the sleep.
def sleep(interval):
'''sleep that ignores EINTR in 2.x on Windows'''
while True:
try:
t = time.time()
time.sleep(interval)
except IOError as e:
if e.errno != errno.EINTR:
raise
interval -= time.time() - t
if interval <= 0:
break
def func(signum, frame):
# note: don't print in a signal handler.
global g_sigint
g_sigint = True
#raise KeyboardInterrupt
signal.signal(signal.SIGINT, func)
g_kill = False
while True:
g_sigint = False
g_kill = not g_kill
print('Running [%d]' % os.getpid())
sleep(2)
if g_kill:
kill(os.getpid(), signal.SIGINT)
if g_sigint:
print('SIGINT')
else:
print('No SIGINT')
讨论
Windows不在系统级[*]实现信号. Microsoft的C运行时实现了标准C所需的六个信号:SIGINT,SIGABRT,SIGTERM,SIGSEGV,SIGILL和SIGFPE.
SIGABRT和SIGTERM仅针对当前流程实施.您可以通过C raise调用处理程序.例如(在Python 3.5中):
>>> import signal, ctypes
>>> ucrtbase = ctypes.CDLL('ucrtbase')
>>> c_raise = ucrtbase['raise']
>>> foo = lambda *a: print('foo')
>>> signal.signal(signal.SIGTERM, foo)
>>> c_raise(signal.SIGTERM)
foo
0
SIGTERM没用.
使用信号模块也无法对SIGABRT做很多事情,因为abort函数会在处理程序返回时终止进程,这会在使用信号模块的内部处理程序时立即发生(它会触发已注册的Python可调用的标记)主线).对于Python 3,您可以改为使用faulthandler模块.或者通过ctypes调用CRT的signal函数来设置ctypes回调作为处理程序.
CRT通过为相应的Windows异常设置Windows structured exception handler来实现SIGSEGV,SIGILL和SIGFPE:
STATUS_ACCESS_VIOLATION SIGSEGV
STATUS_ILLEGAL_INSTRUCTION SIGILL
STATUS_PRIVILEGED_INSTRUCTION SIGILL
STATUS_FLOAT_DENORMAL_OPERAND SIGFPE
STATUS_FLOAT_DIVIDE_BY_ZERO SIGFPE
STATUS_FLOAT_INEXACT_RESULT SIGFPE
STATUS_FLOAT_INVALID_OPERATION SIGFPE
STATUS_FLOAT_OVERFLOW SIGFPE
STATUS_FLOAT_STACK_CHECK SIGFPE
STATUS_FLOAT_UNDERFLOW SIGFPE
STATUS_FLOAT_MULTIPLE_FAULTS SIGFPE
STATUS_FLOAT_MULTIPLE_TRAPS SIGFPE
CRT对这些信号的实现与Python的信号处理不兼容.异常过滤器调用已注册的处理程序,然后返回EXCEPTION_CONTINUE_EXECUTION.但是,Python的处理程序只会为解释器跳转一个标志,以便稍后在主线程中调用已注册的可调用对象.因此,触发异常的错误代码将继续在无限循环中触发.在Python 3中,您可以使用faulthandler模??块来处理这些基于异常的信号.
这就留下了SIGINT,Windows添加了非标准的SIGBREAK.控制台和非控制台进程都可以引发这些信号,但只有控制台进程可以从另一个进程接收它们. CRT通过SetConsoleCtrlHandler注册控制台控制事件处理程序来实现这一点.
控制台通过在附加进程中创建一个新线程来发送控制事件,该进程在kernel32.dll或kernelbase.dll(未记录)中的CtrlRoutine处开始执行.处理程序不在主线程上执行会导致同步问题(例如在REPL中或使用输入).此外,如果在等待同步对象或等待同步I / O完成时被阻塞,则控制事件不会中断主线程.如果SIGINT可以中断,则需要注意避免主线程中的阻塞. Python 3尝试通过使用Windows事件对象解决此问题,该事件对象也可用于应该可被SIGINT中断的等待.
当控制台向进程发送CTRL_C_EVENT或CTRL_BREAK_EVENT时,CRT的处理程序分别调用已注册的SIGINT或SIGBREAK处理程序.还会为控制台在窗口关闭时发送的CTRL_CLOSE_EVENT调用SIGBREAK处理程序. Python默认通过在主线程中运行KeyboardInterrupt来处理SIGINT.但是,SIGBREAK最初是默认的CTRL_BREAK_EVENT处理程序,它调用ExitProcess(STATUS_CONTROL_C_EXIT).
您可以通过GenerateConsoleCtrlEvent将控制事件发送到连接到当前控制台的所有进程.这可以定位属于进程组的进程子集,或目标组0,以将事件发送到连接到当前控制台的所有进程.
进程组不是Windows API的详细记录方面.查询进程组没有公共API,但Windows会话中的每个进程都属于进程组,即使它只是wininit.exe组(服务会话)或winlogon.exe组(交互式会话).通过在创建新进程时传递创建标志CREATE_NEW_PROCESS_GROUP来创建新组.组ID是已创建进程的进程ID.据我所知,控制台是唯一使用进程组的系统,而且只适用于GenerateConsoleCtrlEvent.
当目标ID不是进程组ID时,控制台所执行的操作是未定义的,不应依赖它.如果进程及其父进程都附加到控制台,则向其发送控制事件基本上就像目标是组0一样.如果父进程未附加到当前控制台,则GenerateConsoleCtrlEvent失败,并且os.kill调用TerminateProcess.奇怪的是,如果您定位“系统”进程(PID 4)及其子进程smss.exe(会话管理器),则调用成功但没有任何反应,除了目标被错误地添加到附加进程列表(即GetConsoleProcessList).这可能是因为父进程是“空闲”进程,由于它是PID 0,因此被隐式接受为广播PGID.父进程规则也适用于非控制台进程.定位非控制台子进程不会做任何事情 – 除了通过添加未附加的进程错误地破坏控制台进程列表.我希望您应该只将控制事件发送到组0或通过CREATE_NEW_PROCESS_GROUP创建的已知进程组.
不要依赖于能够将CTRL_C_EVENT发送到除组0之外的任何内容,因为它最初在新进程组中被禁用.将此事件发送到新组并非不可能,但目标进程首先必须通过调用SetConsoleCtrlHandler(NULL,FALSE)来启用CTRL_C_EVENT.
CTRL_BREAK_EVENT是您可以依赖的所有内容,因为它无法禁用.发送此事件是一种优雅地杀死使用CREATE_NEW_PROCESS_GROUP启动的子进程的简单方法,假设它具有Windows CTRL_BREAK_EVENT或C SIGBREAK处理程序.如果没有,默认处理程序将终止进程,将退出代码设置为STATUS_CONTROL_C_EXIT.例如:
>>> import os, signal, subprocess
>>> p = subprocess.Popen('python.exe',
... stdin=subprocess.PIPE,
... creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
>>> os.kill(p.pid, signal.CTRL_BREAK_EVENT)
>>> STATUS_CONTROL_C_EXIT = 0xC000013A
>>> p.wait() == STATUS_CONTROL_C_EXIT
True
请注意,CTRL_BREAK_EVENT未发送到当前进程,因为该示例以子进程的进程组为目标(包括连接到控制台的所有子进程,依此类推).如果示例使用了组0,那么当前进程也会被杀死,因为我没有定义SIGBREAK处理程序.让我们尝试一下,但设置一个处理程序:
>>> ctrl_break = lambda *a: print('^BREAK')
>>> signal.signal(signal.SIGBREAK, ctrl_break)
>>> os.kill(0, signal.CTRL_BREAK_EVENT)
^BREAK
[*]
Windows有asynchronous procedure calls(APC)将目标函数排入线程.有关Windows APC的深入分析,请参阅文章Inside NT’s Asynchronous Procedure Call,尤其是阐明内核模式APC的作用.您可以通过QueueUserAPC将用户模式APC排队到一个线程.它们也会在ReadFileEx和WriteFileEx排队等待I / O完成例程.
当线程进入可警告等待时(例如,WaitForSingleObjectEx或SleepEx,其中bAlertable为TRUE),执行用户模式APC.另一方面,内核模式APC立即被调度(当IRQL低于APC_LEVEL时).它们通常由I / O管理器用于在发出请求的线程的上下文中完成异步I / O请求包(例如,将数据从IRP复制到用户模式缓冲区).有关显示APC如何影响可警告和不可警报等待的表,请参阅Waits and APCs.请注意,内核模式APC不会中断等待,而是由等待例程在内部执行.
Windows可以使用APC实现类似POSIX的信号,但实际上它使用其他方法来实现相同的目的.例如:
窗口消息可以发送并发布到共享调用thread’s desktop且处于相同或更低完整性级别的所有线程.当线程调用PeekMessage或GetMessage时,发送窗口消息会将其置于系统队列中以调用窗口过程.发布消息会将其添加到线程的消息队列中,该消息队列的默认配额为10,000条消息.具有消息队列的线程应具有消息循环以通过GetMessage和DispatchMessage处理队列.仅控制台进程中的线程通常没有消息队列.但是,控制台主机进程conhost.exe显然可以.单击关闭按钮时,或者通过任务管理器或taskkill.exe终止控制台的主进程时,WM_CLOSE消息将发布到控制台窗口的线程的消息队列中.控制台轮流向其所有连接的进程发送CTRL_CLOSE_EVENT.如果进程处理该事件,则在强制终止之前,它会在5秒内正常退出.
python兼职平台信号处理_如何在Windows机器上处理python中的信号相关推荐
- python安装numpy模块教程_如何在windows机器上安装python 3.6的matplotlib和numpy模块?...
如果你在python(3.6)命令提示符Windows上执行以下命令时收到无效的Systemax错误:import matplotlib import scipy import numpy 在浏览器下 ...
- python兼职平台信号处理_基于Python的数字信号处理初步
作者:许欢 来源:EETOP 行者无疆(论坛usrname:ICNO.1) 的博客 Python 是目前的热门语言,一直觉得掌握一门编程语言对作为搞技术的来说还是很有必要的,结合工作中能用到的一些数据 ...
- vscode重置应用程序_如何在Windows 10上重置应用程序的数据
vscode重置应用程序 With Windows 10's Anniversary Update, you can now reset an app's data without actually ...
- skype自动回复_如何在Windows 10上阻止Skype自动启动
skype自动回复 Microsoft 微软 The Skype app included with Windows 10 now has a notification area icon. That ...
- python 管理windows客户端_在远程windows客户端上执行python脚本
我正在使用paramiko在远程windows服务器上执行命令.我能够执行dir之类的命令并提取输出,但是执行python脚本似乎失败了.不会引发错误消息.在 下面是我的代码片段:def ssh_co ...
- ffmpeg添加到环境变量_如何在Windows 10上下载和安装FFmpeg
如何在Windows 10上下载和安装FFmpeg FFmpeg是一种流行的开源工具,用于对音频和视频文件执行多项操作.这些操作包括多路复用,解复用,编码,解码,过滤,流式传输等. 它还用于缩放和旋转 ...
- 如何在Windows 10上安装Python
Installing and using Python on Windows 10 is very simple. The installation procedure involves just t ...
- shell bash脚本_如何在Windows 10上创建和运行Bash Shell脚本
shell bash脚本 With the arrival of Windows 10's Bash shell, you can now create and run Bash shell scri ...
- python兼职平台信号处理_Python模块之信号(signal)
在了解了Linux的信号基础之 后,Python标准库中的signal包就很容易学习和理解.signal包负责在Python程序内部处理信号,典型的操作包括预设信号处理函数,暂 停并等待信号,以及定时 ...
最新文章
- vmware 共享文件夹(win10下的vmware安装了centos7)
- nginx视频直播/点播服务干货分享
- MySQL数据库设计总结
- XGBoost相关知识-1
- 美团配送资金安全治理之对账体系建设
- 中科微研携手-农业大健康·李喜贵:从玉农业谋定功能性农业
- mysql8.0.22 win7_ArcGIS10.8地理信息软件中英文版安装教程
- Windows 系统管理
- php日期时间代码,PHP日期计算
- php父子遍历,php无限分类父子追溯方法
- 微信开发者工具 wxmi修改模版颜色_网站建设公司讲解:微信小程序的开发者工具界面...
- js 对象的_proto_属性 和函数的prototype属性分析
- 如何通过a/a中的href刷新当前界面
- 四年级计算机考试反思,四年级期中考试总结反思三篇
- 在Windows本地安装ElasticSearch和Kibana
- 帝国cms ajax,帝国CMS注册体验加强 ajax检测用户名和密码
- GoLang - Go中Mocking(3)
- Python 爬取微信公众号文章
- FileZilla文件传输失败问题
- 游戏多开计算机内存不足,技术宅 解决天刀多开单开内存不足问题
热门文章
- axure怎么做5秒倒计时_装修隔音怎么做,进屋秒变“静音”模式
- 【PDF下载】无意中发现的另三本统计学入门好书
- SAP UI5 应用开发教程之四十七 - 如何自定义 SAP UI5 字符串类型输入字段的校验逻辑
- SAP Spartacus 服务器端渲染处理内存泄漏的准则
- SAP Spartacus user role页面的checkbox设计明细介绍
- Angular async pipe在Component html模板中的一个实际应用
- 如何判断一个SAP CRM UI能否被扩展
- 使用SAP OData offline库实现Android应用的离线(offline)模式
- why my SAP CRM One Order custom callback is not called
- view detail data in gateway error log