내 이해에 따르면 -1을 반환 하고 ...로 설정할 수있는 (그리고 수행하는) SIGPIPE
a의 결과로만 발생할 수 있습니다. 왜 우리는 신호의 추가 오버 헤드를 가지고 있습니까? 파이프로 작업 할 때마다 무시 하고 그 결과로 어떤 고통도 느끼지 못했습니다. 뭔가 놓치고 있습니까?write()
errno
EPIPE
SIGPIPE
답변:
나는 이전에 받아 들인 대답을 사지 않습니다. 사전이 아닌으로 실패 SIGPIPE
할 때 정확히 생성됩니다. 실제로 전역 신호 처리를 변경 하지 않고 피할 수있는 안전한 방법 중 하나 는 일시적으로으로 마스킹하고을 수행 한 다음 (제로 타임 아웃으로) 수행 하여 보류중인 신호 를 소비 하는 것입니다. 다시 마스크를 해제하기 전에 프로세스가 아닌 호출 스레드).write
EPIPE
SIGPIPE
pthread_sigmask
write
sigtimedwait
SIGPIPE
그 이유 SIGPIPE
가 훨씬 더 간단 하다고 생각합니다 . 입력을 계속 읽고 어떻게 든 변환하고 출력을 쓰는 순수한 "필터"프로그램에 대한 정상적인 기본 동작을 설정하는 것입니다. 를 사용하지 SIGPIPE
않으면 이러한 프로그램이 명시 적으로 쓰기 오류를 처리하고 즉시 종료하지 않는 한 (어쨌든 모든 쓰기 오류에 대해 원하는 동작이 아닐 수 있음) 출력 파이프가 닫혀 있어도 입력이 부족할 때까지 계속 실행됩니다. 물론 SIGPIPE
명시 적으로 확인 EPIPE
하고 종료 하여의 동작을 복제 할 수 있지만의 전체 목적은 SIGPIPE
프로그래머가 게으른 경우 기본적으로이 동작을 달성하는 것입니다 .
프로그램이 I / O를 기다리거나 일시 중단 될 수 있기 때문입니다. SIGPIPE는 프로그램을 비동기 적으로 중단하여 시스템 호출을 종료하므로 즉시 처리 할 수 있습니다.
최신 정보
파이프 라인을 고려하십시오 A | B | C
.
명확성을 위해 B가 표준 복사 루프라고 가정합니다.
while((sz = read(STDIN,bufr,BUFSIZE))>=0)
write(STDOUT,bufr,sz);
B
종료 될 때 부터 데이터를 기다리는 read (2) 호출 에서 차단 됩니다. write (2) 의 리턴 코드를 기다리면 B는 언제 그것을 볼 수 있습니까? 물론 대답은 A가 더 많은 데이터를 쓸 때까지가 아닙니다 (긴 기다릴 수 있습니다. A가 다른 것에 의해 차단되면 어떻게 될까요?). 그건 그렇고, 이것은 또한 우리에게 더 간단하고 깨끗한 프로그램을 허용합니다. 쓰기 오류 코드에 의존했다면 다음과 같은 것이 필요합니다.A
C
while((sz = read(STDIN,bufr,BUFSIZE))>=0)
if(write(STDOUT,bufr,sz)<0)
break;
또 다른 업데이트
아하, 당신은 쓰기 동작에 대해 혼란스러워합니다. 보류중인 쓰기가있는 파일 설명자가 닫히면 SIGPIPE가 바로 발생합니다. 쓰기는 결국 -1을 반환하지만 신호의 요점은 쓰기가 더 이상 가능하지 않다는 것을 비동기 적으로 알리는 것입니다. 이것은 파이프의 전체 우아한 코 루틴 구조가 UNIX에서 작동하도록 만드는 요소의 일부입니다.
이제 여러 UNIX 시스템 프로그래밍 책에서 전체 토론을 가리킬 수 있지만 더 나은 답이 있습니다. 직접 확인할 수 있습니다. 간단한 B
프로그램을 작성하세요 [1]-이미 배짱이 있고, 필요한 것은 a main
와 일부 포함입니다-그리고 SIGPIPE
. 다음과 같은 파이프 라인 실행
cat | B | more
다른 터미널 창에서 디버거를 B에 연결하고 B 신호 처리기 내부에 중단 점을 넣습니다.
이제 더 많은 것을 죽이고 B는 신호 처리기에서 중단됩니다. 스택을 조사하십시오. 당신은 것을 찾을 수 읽기가 아직 보류 중입니다. 에 의해 반환 된 결과에서 진행 핸들러 신호와 반환, 및 살펴 보자 쓰기 - 할 다음 일 -1.
[1] 당연히 B 프로그램을 C로 작성합니다. :-)
SIGPIPE
되어 있지 하지만 중, 읽기 중 전달 write
. 당신은 그것을 테스트하는 C 프로그램을 작성해야합니다, 단지 실행하지 않는 cat | head
, 그리고 pkill head
별도의 터미널이다. 당신은 cat
기다릴 read()
때 행복하게 살아가는 것을 볼 수있을 것입니다.- cat
단지 당신이 무언가를 입력하고 엔터를 눌렀을 때만 출력을 쓰려고했기 때문에 깨진 파이프와 함께 죽습니다.
SIGPIPE
은을 ( B
를 B
) 시도 할 때까지 생성되지 read
않기 때문에 차단 된 동안에 전달할 수 없습니다 . 동시에 호출하는 동안 스레드는 "I / O를 기다리거나 일시 중단"할 수 없습니다 . SIGPIPE
B
write
write
SIGPIPE
차단 된 동안 제기되는 것을 보여주는 전체 프로그램을 게시 할 수 있습니까 read
? 나는 전혀 그 동작을 재현하지 (내가 처음에이 수락 이유를 실제로 확실하지 않다) 수
https://www.gnu.org/software/libc/manual/html_mono/libc.html
이 링크는 다음과 같이 말합니다.
파이프 또는 FIFO는 양쪽 끝에서 동시에 열려야합니다. 쓰기 프로세스가없는 파이프 또는 FIFO 파일에서 읽는 경우 (아마도 파일을 모두 닫았거나 종료했기 때문에) 읽기는 파일 끝을 반환합니다. 읽기 프로세스가없는 파이프 또는 FIFO에 쓰는 것은 오류 조건으로 처리됩니다. SIGPIPE 신호를 생성 하고 신호가 처리되거나 차단되면 오류 코드 EPIPE와 함께 실패합니다.
— 매크로 : int SIGPIPE
깨진 파이프. 파이프 또는 FIFO를 사용하는 경우 다른 프로세스가 쓰기를 시작하기 전에 한 프로세스가 읽기를 위해 파이프를 열도록 애플리케이션을 설계해야합니다. 읽기 프로세스가 시작되지 않거나 예기치 않게 종료 되면 파이프 또는 FIFO에 쓰기가 SIGPIPE 신호를 발생시킵니다. SIGPIPE가 차단, 처리 또는 무시되면 문제가되는 호출이 대신 EPIPE로 실패합니다.
파이프 및 FIFO 특수 파일은 파이프 및 FIFO에서 자세히 설명합니다.
기계 정보 :
Linux 3.2.0-53-generic # 81-Ubuntu SMP Thu Aug 22 21:01:03 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux
gcc 버전 4.6.3 (Ubuntu / Linaro 4.6.3-1ubuntu5)
아래에이 코드를 작성했습니다.
// Writes characters to stdout in an infinite loop, also counts
// the number of characters generated and prints them in sighandler
// writestdout.c
# include <unistd.h>
# include <stdio.h>
# include <signal.h>
# include <string.h>
int writeCount = 0;
void sighandler(int sig) {
char buf1[30] ;
sprintf(buf1,"signal %d writeCount %d\n", sig, writeCount);
ssize_t leng = strlen(buf1);
write(2, buf1, leng);
_exit(1);
}
int main() {
int i = 0;
char buf[2] = "a";
struct sigaction ss;
ss.sa_handler = sighandler;
sigaction(13, &ss, NULL);
while(1) {
/* if (writeCount == 4) {
write(2, "4th char\n", 10);
} */
ssize_t c = write(1, buf, 1);
writeCount++;
}
}
// Reads only 3 characters from stdin and exits
// readstdin.c
# include <unistd.h>
# include <stdio.h>
int main() {
ssize_t n ;
char a[5];
n = read(0, a, 3);
printf("read %zd bytes\n", n);
return(0);
}
산출:
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 11486
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 429
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 281
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 490
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 433
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 318
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 468
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 11866
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 496
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 284
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 271
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 416
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 11268
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 427
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 8812
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 394
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 10937
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 10931
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 3554
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 499
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 283
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 11133
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 451
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 493
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 233
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 11397
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 492
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 547
$ ./writestdout | ./readstdin
read 3 bytes
signal 13 writeCount 441
모든 경우 SIGPIPE
에 쓰기 프로세스에 의해 3 개 이상의 문자가 쓰여진 후에 만 수신 된다는 것을 알 수 있습니다 .
이것은 SIGPIPE
읽기 프로세스가 종료 된 직후에 생성되지 않고 닫힌 파이프에 더 많은 데이터를 쓰려고 시도한 후에 생성 된다는 것을 증명 하지 않습니까?
write
.