已處理的 SIGINT 是否會影響與子程序的管道通信?
我有一個互動式 C 程序,它從終端讀取一個片語,併計算一系列字謎。我還有一個 Perl 程序,它從 STDIN 讀取和緩衝行,直到接收到保留的“輸入結束”標記,對行進行排序,將它們組織成列並將它們發送到 STDOUT。C 程序使用 BSD/MacOS
popen()
以單個雙向管道啟動 Perl 程序,並fprintf()
在管道上生成 anagrams,直到生成所有 anagrams;發送“輸入結束”標記,然後getline()
在管道上發出 ’s 以讀取並列印格式化的結果。它工作正常。但是我在 C 程序中添加了一個 SIGINT 處理程序,這樣我就可以中斷一個長時間執行的字謎,列印它到目前為止的任何結果,並循環獲取更多終端輸入。處理程序設置一個標誌,主程序在寫入管道後檢查該標誌。如果它被設置,它會跳出字謎循環並繼續進行,就像循環自然結束一樣:它發送輸入結束字元串,並讀回格式化的結果。
它爆發了。輸入
fprintf
結束得到一個正常的返回碼;但第一個getline
返回一個指示 EOF 的空指針,所以我沒有得到任何部分結果。C 程序按預期正常繼續。我在文件中找不到任何內容表明處理的 SIGINT 會影響任何打開的管道,但我想不出還有什麼會阻止我從 Perl 程序接收任何內容。
SIGINT
信號到達前台程序組中的每個程序;前台程序組通常包括任何popen
執行,/* popen.c */ #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> void poke(int unused) { fprintf(stderr, "sigint - C\n"); } int main(void) { FILE *fh; signal(SIGINT, poke); fh = popen( "exec perl -e '$SIG{INT}=sub {warn q{ouch}};sleep 1 while 1'", "r+"); if (!fh) abort(); while (1) sleep(1); return 42; }
可以通過以下方式驗證:
$ make popen $ ./popen ^Csigint - C ouch at -e line 1. ^Csigint - C ouch at -e line 1. ^\Quit
因此,所有程序都必須對信號進行處理,否則可以在終端中關閉信號。細節會因語言而異,但要忽略 Perl 中的信號,可以簡單地忽略它:
$SIG{INT} = "IGNORE";
另一種選擇是阻止父程序中的信號,儘管後續程序可能會安裝自己的信號處理程序。
另一種選擇是
ISIG
在終端中啟用該標誌。在這種情況下control
+c
不會導致向前台程序組發送信號;相反,一個字元將可供某些程序讀取。有關詳細資訊,請參閱termios
手冊頁(手冊頁部分因作業系統而異)。像 curses 這樣的介面在這裡可能是典型的,儘管可以改為進行適當的tcsetaddr(3)
呼叫來啟用ISIG
。#!/usr/bin/env perl # example script showing how control+c can be read as a key use strict; use warnings; use Curses; initscr; noecho; raw; # enables ISIG, among other things while (1) { my $ch = getchar() // die "getchar failed??"; last if $ch eq 'q'; move 0, 0; clrtoeol; addstring sprintf "key: %vx", $ch; } endwin;
這應該在按下+
key: 3
時顯示;不會向前台程序組發送信號。鍵入退出。control``c``q