[英]Windows console signal handling for subprocess c++
假設我們有一個用C ++編寫的小程序,如下所示。
該程序本身有意不通過WinAPI調用SetConsoleCtrlHandler
執行信號處理-這是問題的重要組成部分。
#include <stdio.h>
#include <stdlib.h>
int main() {
while(true) {
int status = system("EXTERNAL COMMAND");
printf("RESULT STATUS = %d\n", status);
}
}
當在終端中按下Ctrl+C
組合鍵時,上面的程序會有完全不同的行為,具體取決於調用了哪個"EXTERNAL COMMAND"
1)如果外部命令處於pause
,程序將處於無限循環狀態,逐步調用pause
命令,並"RESULT STATUS = 0" many times
打印"RESULT STATUS = 0" many times
,而不會通過進程終止強制終止。
2)如果choice
外部命令,程序將在Ctrl+C
后立即終止。 它不會打印任何內容,也不會從system
調用中返回。
3)如果將外部命令set /P VAR=
,則程序會產生很多有趣的行為。 當Ctrl+C
,程序將打印“ RESULT STATUS = 1”並繼續工作,直到執行第一個異步調用為止。
第一種和第二種情況可以通過以下方式進行解釋。 終端窗口位於用戶輸入和目標程序之間,因此當用戶按下Ctrl+C
,終端窗口本身將向目標進程執行調度信號。
因此,某些子hConsole = GetStdHandle(STD_OUTPUT_HANDLE)
可以通過hConsole = GetStdHandle(STD_OUTPUT_HANDLE)
手動接收終端處理程序,並執行自己的信號處理。 另一個子進程不執行此操作,因此信號傳遞到父進程並終止它。
但是第三種情況引起了很大的疑問。 如果子進程攔截SIGINT
,為什么父進程在第一次異步調用后執行終止。 如果不是,為什么它不會立即終止以及為什么以及如何打印“ RESULT STATUS = 1”並繼續工作。
謝謝
Windows中沒有Unix信號,至少不是來自內核的信號。 也就是說,Windows和Windows API基本上是基於C編程語言的,它是與Unix一起開發的,確實需要六個信號 。 Windows中的C運行時在進程內模擬SIGABRT
和SIGTERM
(例如,與C raise
一起使用)。 對於SIGSEGV
, SIGILL
和SIGFPE
它使用OS異常處理程序。 在控制台應用程序中,標准SIGINT
和非標准SIGBREAK
與C運行時的控制台控制處理程序關聯,通常是通過SetConsoleCtrlHandler
注冊的第一個處理程序。 CTRL_C_EVENT
映射到SIGINT
信號處理程序,所有其他( CTRL_BREAK_EVENT
, CTRL_CLOSE_EVENT
)都映射到SIGBREAK
處理程序。
控制台控制事件由控制台主機(conhost.exe)發送,控制台主機通過使會話服務器(csrss.exe)在客戶端進程中創建線程來實現此目的。 該線程從CtrlRoutine
中未CtrlRoutine
函數開始,該函數會遍歷已注冊的控制處理程序,直到其中一個通過返回true來處理事件。 如果它們都不處理事件,則默認處理程序調用ExitProcess(STATUS_CONTROL_C_EXIT)
。 請注意, SetConsoleCtrlHandler(NULL, TRUE)
設置一個使CtrlRoutine
忽略CTRL_C_EVENT
標志,並且該標志由子進程繼承,並且在使用標志CREATE_NEW_PROCESS_GROUP
創建進程時默認情況下啟用。 同樣,對於CTRL_CLOSE_EVENT
,會話服務器會給每個進程5秒鍾來處理事件並自行退出,否則它將強制終止該進程。
要了解CMD的內部PAUSE
命令發生了什么,請參閱SetConsoleMode ,尤其是ENABLE_PROCESSED_INPUT
。 PAUSE
調用C _getch
,這會暫時將控制台輸入模式設置為0。在禁用處理輸入模式的情況下,Ctrl + C只是讀為“ \\ x03”而不是生成CTRL_C_EVENT
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.