簡體   English   中英

Windows控制台信號處理,用於子進程C ++

[英]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運行時在進程內模擬SIGABRTSIGTERM (例如,與C raise一起使用)。 對於SIGSEGVSIGILLSIGFPE它使用OS異常處理程序。 在控制台應用程序中,標准SIGINT和非標准SIGBREAK與C運行時的控制台控制處理程序關聯,通常是通過SetConsoleCtrlHandler注冊的第一個處理程序。 CTRL_C_EVENT映射到SIGINT信號處理程序,所有其他( CTRL_BREAK_EVENTCTRL_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM