Buforowanie wejścia/wyjścia (IO buffering) istnieje w języku C od czasu wprowadzenia standardowej biblioteki (stdio). Wprowadzono je w celu zwiększenia wydajności operacji odczytu i zapisu, ponieważ odwołania do dysku lub urządzeń są kosztowną operacją pod względem czasu, a buforowanie pozwala na zmniejszenie ich liczby.
Nieznajomość działania buforowania może prowadzić do nieoczekiwanych opóźnień w operacjach wejścia/wyjścia, utraty danych w przypadku awarii programu, błędów w pracy z wieloma wątkami (szczególnie w przypadku stdout/stderr), a także błędów synchronizacji między procesami lub systemami.
Wiedząc, że strumienie plikowe mogą być buforowane, buforowane liniowo lub buforowane w sposób niebezpieczny, ważne jest, aby używać funkcji wymuszającej opróżnienie bufora (fflush()), poprawnie zamykać pliki (fclose()), a także mądrze łączyć pracę ze stdin, stdout i stderr. Buforowanie również zależy od typu strumienia (na przykład stdout jest opróżniane przy wypisywaniu znaku w związanym ze terminalem strumieniu, ale nie zawsze — jeśli to jest plik).
Przykład kodu:
#include <stdio.h> int main() { printf("Hello"); // sleep(10); // przed fflush nie będzie wyjścia fflush(stdout); // od razu wypisuje bufor na ekran return 0; }
Kluczowe cechy:
fflush() — podstawowe narzędzie do ręcznego opróżniania buforaCzy można polegać na tym, że dane printf natychmiast pojawią się na ekranie?
Nie, jeśli wyjście idzie nie do terminala, ale na przykład do pliku — linie nie pojawią się, dopóki nie nastąpi opróżnienie bufora lub nie zostanie osiągnięty limit buforowania. Nawet w terminalu, linia bez może nie pojawić się od razu. Używaj fflush(stdout); dla natychmiastowego wyjścia.
Co się stanie, jeśli wywołam fflush(stdin)?
To niezdefiniowane zachowanie zgodnie z standardem C. Niektóre kompilatory/platformy mogą czyścić bufor strumienia wejściowego, ale nie jest to gwarantowane przez standard, a takie podejście nie jest przenośne i potencjalnie niebezpieczne.
Czy printf i fprintf(stderr, ...) można uważać za równoważne dla natychmiastowego wyjścia?
Nie. Standardowe wyjście (stdout) zazwyczaj jest buforowane całkowicie lub liniowo, stderr zgodnie ze standardem zawsze jest buforowane w sposób niebezpieczny. To znaczy, że wyjście w stderr pojawia się na ekranie od razu, a w stdout — nie.
fflush(stdin) do czyszczenia bufora wejściowegoProgram pisze plik dziennika przez printf, ale nie wywołuje fflush(stdout) i nie zamyka pliku przy awaryjnym zakończeniu.
Zalety:
Wady:
Program po każdej ważnej wpisie do dziennika wywołuje fflush(stdout) lub pisze krytyczne komunikaty do stderr.
Zalety:
Wady: