Programing

SIGPIPE가 존재하는 이유는 무엇입니까?

lottogame 2020. 9. 7. 22:28
반응형

SIGPIPE가 존재하는 이유는 무엇입니까?


내 이해에 따르면 -1을 반환 하고 ...로 설정할 수있는 (그리고 수행하는) SIGPIPEa의 결과로만 발생할 수 있습니다. 왜 우리는 신호의 추가 오버 헤드를 가지고 있습니까? 파이프로 작업 할 때마다 무시 하고 그 결과로 어떤 고통도 느끼지 못했습니다. 뭔가 놓치고 있습니까?write()errnoEPIPESIGPIPE


나는 이전에 받아 들인 대답을 사지 않습니다. 사전이 아닌으로 실패 SIGPIPE할 때 정확히 생성됩니다. 실제로 전역 신호 처리를 변경 하지 않고 피할 수있는 안전한 방법 중 하나 는 일시적으로으로 마스킹하고을 수행 한 다음 (제로 타임 아웃으로) 수행 하여 보류중인 신호 를 소비 하는 것입니다. 다시 마스크를 해제하기 전에 프로세스가 아닌 호출 스레드).writeEPIPESIGPIPEpthread_sigmaskwritesigtimedwaitSIGPIPE

그 이유 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가 다른 것에 의해 차단되면 어떻게 될까요?). 그건 그렇고, 이것은 또한 우리에게 더 간단하고 깨끗한 프로그램을 허용합니다. 쓰기 오류 코드에 의존했다면 다음과 같은 것이 필요합니다.AC

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로 작성합니다. :-)


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에서 자세히 설명합니다.


나는 파이프에 쓰는 모든 것에 많은 코드를 요구하지 않고 오류 처리를 올바르게 얻는 것이라고 생각합니다.

일부 프로그램은 반환 값을 무시합니다 write(). 없이 SIGPIPE그들은 쓸데없이 모든 출력을 생성합니다.

반환 값을 확인하는 프로그램은 write()실패 할 경우 오류 메시지를 인쇄합니다. 이것은 전체 파이프 라인에 대해 실제로 오류가 아니므로 깨진 파이프에는 부적절합니다.


기계 정보 :

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읽기 프로세스가 종료 된 직후에 생성되지 않고 닫힌 파이프에 더 많은 데이터를 쓰려고 시도한 후에 생성 된다는 것을 증명 하지 않습니까?

참고 URL : https://stackoverflow.com/questions/8369506/why-does-sigpipe-exist

반응형