2013-05-05 9 views
16

Ten program generuje SIGPIPE po podłączeniu go do "head -n 1" po losowym czasie. Rozumiem, że ponieważ po pierwszym wierszu karmimy więcej "head -n 1", spodziewamy się, że wygeneruje on SIGPIPE, ale zamiast tego osiągnie liczbę losową (zwykle> 20 i < 200) przed zakończeniem. Każdy pomysł, dlaczego?Dlaczego ten program C generuje SIGPIPE później niż oczekiwano?

#include <stdio.h> 
#include <stdlib.h> 

main() 
{ 
    int i; 
    char *s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"; 

    i = 0; 
    while (1) { 
    fputs(s, stdout); 
    fflush(stdout); 
    fprintf(stderr, "Iteration %d done\n", i); 
    i++; 
    } 
} 

To nie jest praca domowa, po prostu coś w notatkach mojego profesora, czego nie rozumiem.

+0

Ehm, ** 'const' **' char * s = ... ' –

+2

Trzeba czasu, aby wypchać tytoń. – Kaz

Odpowiedz

8

To kaprysy planowania.

Twój producent - nazwijmy to alphabeta - jest w stanie pracować przez pewien czas przed head kwota jest w stanie odczytać i exit (łamiąc w ten sposób rury).

To "pewna ilość czasu", oczywiście, jest zmienna.

Czasami alphabeta działa 20 razy, zanim head może odczytać stdin i wyjść. Czasami 200 razy. W moim systemie czasami 300 lub 1000 lub 2000 razy. W rzeczywistości może teoretycznie zapętlić się do wydajności rury łączącej producenta i konsumenta.

Do demonstracji, niech wprowadzają pewne opóźnienie, dzięki czemu możemy być pewnym, że head tkwi w read() przed alphabeta produkuje pojedynczą linię wyjścia:

so$ { sleep 5; ./alphabeta; } | head -n 1 
ABCDEFGHIJKLMNOPQRSTUVWXYZ 
Iteration 0 done 

(NB nie jest zagwarantowane, że alphabeta będzie Iteruj tylko raz w powyższym, ale na nieobciążonym systemie, to będzie mniej więcej zawsze: head będzie gotowy, a jego odczyt/zakończenie stanie się bardziej lub mniej natychmiastowe).

Zegarek zamiast tego, co się dzieje, gdy sztucznie opóźniać head:

so$ ./alphabeta | { sleep 2; head -n 1; } 
Iteration 0 done 
... 
Iteration 2415 done # <--- My system *pauses* here as pipe capacity is reached ... 
Iteration 2416 done # <--- ... then it resumes as head completes its first read() 
... 
Iteration 2717 done # <--- pipe capacity reached again; head didn't drain the pipe 
ABCDEFGHIJKLMNOPQRSTUVWXYZ 

Tak na marginesie, @R .. ma rację w swoich uwagach, że SIGPIPE jest synchroniczny. W twoim przypadku pierwszy wywołany przez fflush zapis do zepsutej rury (po wyjściu head) będzie synchronicznie generował sygnał. To jest documented behavior.

4

Myślę, że to po prostu dlatego, że sygnały są asynchroniczne.

Aktualizacja: jak zauważyli inni (dokładniej wiele, w tym SIGPIPE), nie są. To była przemyślana odpowiedź :)

+0

Brak buforowania stdio. –

+5

SIGPIPE jest sygnałem synchronicznym. –

+0

@R .. 'stdio' nie buforuje za' fflush'. – Kevin

0

Zapisy na gniazdach są buforowane i asynchroniczne, więc generalnie nie otrzymasz błędu wynikającego z określonego zapisu do następnego odczytu lub zapisu).

+5

Nie jestem pewien, dlaczego zapisy na gniazdach są istotne dla pytania o wyprowadzane sygnały wyjściowe. –

0

Polecenie używa stdio do odczytu stdin, a więc pierwsze getc nie powraca, dopóki bufor nie jest pełny lub EOF, w zależności od tego, co nastąpi wcześniej.

+0

Możesz to sprawdzić za pomocą strace. –

+1

Nie, to przepustowość i harmonogramowanie rur. Zobacz moją odpowiedź. – pilcrow

+0

Jak powiedział pilcrow, to planowanie. Bufor w kernelu (zwykle 64-128 KiB) nie wypełnia się w tym przypadku, ponieważ zapisywane jest tylko około 200 * 27 = 5,4 KB danych. –

Powiązane problemy