0Pricing
C Academy · Lekcja

Potoki

Komunikacja rodzic–dziecko

Potoki to bezpłatna lekcja C Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C Academy zawiera 4 lekcji w sumie.

Czym jest potok

Potok to jednokierunkowy kanał komunikacji między powiązanymi procesami. Jeden proces zapisuje do niego bajty, a drugi je odczytuje — przypomina to taśmociąg z danymi.

Dwa deskryptory plików

Wywołanie pipe() wypełnia tablicę złożoną z dwóch elementów: fd[0] to koniec przeznaczony do odczytu, a fd[1] to koniec przeznaczony do zapisu. Dane zapisane do fd[1] można odczytać z fd[0].

#include <unistd.h>
#include <stdio.h>

int make_pipe(int fd[2]) {
    if (pipe(fd) < 0) { perror("pipe"); return -1; }
    /* fd[0] read end, fd[1] write end */
    return 0;
}

Połączenie z fork

Po wywołaniu fork() zarówno proces nadrzędny, jak i potomny mają dostęp do deskryptorów potoku. W ten sposób proces nadrzędny i potomny komunikują się ze sobą: jeden zapisuje, a drugi odczytuje.

Zamykanie nieużywanych końców

Każdy proces powinien zamknąć nieużywany koniec. Proces odczytujący zamyka koniec zapisu, a proces zapisujący — koniec odczytu. W przeciwnym razie proces odczytujący nigdy nie otrzyma informacji o końcu pliku.

#include <unistd.h>

void parent_as_writer(int fd[2]) {
    close(fd[0]);              /* parent will not read */
    write(fd[1], "hello", 5);  /* parent writes */
    close(fd[1]);              /* signal EOF to reader */
}

Przykład procesu nadrzędnego i potomnego

Proces nadrzędny zapisuje komunikat, a proces potomny go odczytuje. Każdy z nich zamyka niepotrzebny koniec potoku.

#include <unistd.h>
#include <stdio.h>

void demo(int fd[2]) {
    if (fork() == 0) {           /* child: reader */
        close(fd[1]);
        char buf[64];
        ssize_t n = read(fd[0], buf, sizeof buf - 1);
        buf[n] = 0;
        printf("child got: %s\n", buf);
        close(fd[0]);
    } else {                     /* parent: writer */
        close(fd[0]);
        write(fd[1], "hi child", 8);
        close(fd[1]);
    }
}

Odczyt zwraca EOF

Gdy wszystkie końce zapisu zostaną zamknięte, read zwraca 0, sygnalizując koniec pliku. Jeśli któryś koniec zapisu pozostanie otwarty, proces odczytujący będzie bez końca blokowany w oczekiwaniu na kolejne dane — to częsty błąd.

Pojemność potoku i blokowanie

Potok ma ograniczony bufor (często 64 KB). Gdy bufor się zapełni, write blokuje się, dopóki proces odczytujący nie pobierze danych. Gdy bufor jest pusty, read blokuje się do momentu nadejścia danych. Ta kontrola przepływu synchronizuje oba procesy.

Przekierowanie za pomocą dup2

dup2 może zastąpić standardowe wejście lub wyjście procesu końcem potoku. W ten sposób powłoki implementują cmd1 | cmd2, łącząc wyjście jednego polecenia z wejściem kolejnego.

#include <unistd.h>

void stdout_to_pipe(int fd[2]) {
    close(fd[0]);
    dup2(fd[1], STDOUT_FILENO); /* writes to stdout go into pipe */
    close(fd[1]);
}

Potoki nazwane (FIFO)

Zwykły potok łączy tylko powiązane procesy. Potok nazwany (FIFO), utworzony za pomocą mkfifo, pojawia się w systemie plików, dzięki czemu niepowiązane procesy mogą otworzyć go po ścieżce i komunikować się ze sobą.

#include <sys/stat.h>

int make_fifo(const char *path) {
    return mkfifo(path, 0666); /* creates a FIFO file */
}

Zagrożenie SIGPIPE

Zapis do potoku, którego koniec odczytu został zamknięty, powoduje wysłanie sygnału SIGPIPE, który domyślnie kończy proces. Należy zignorować ten sygnał albo sprawdzać, czy write zwróciło błąd EPIPE.

Kiedy używać potoków

Potoki doskonale nadają się do prostowego, jednokierunkowego przesyłania danych między procesem nadrzędnym i potomnym oraz do łączenia programów w potoki. W przypadku komunikacji dwukierunkowej lub między niepowiązanymi procesami warto rozważyć FIFO, sockety albo pamięć współdzieloną.

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat potoków.

Podsumowanie

Dowiedziano się, jak używać potoków do komunikacji między procesem nadrzędnym i potomnym.

  • pipe() udostępnia fd[0] (odczyt) i fd[1] (zapis)
  • Należy połączyć go z fork i zamknąć nieużywane końce
  • read zwraca 0 na końcu pliku, gdy wszystkie końce zapisu zostaną zamknięte
  • FIFO łączy niepowiązane procesy; należy uważać na SIGPIPE

Często zadawane pytania

Czy lekcja „Potoki” jest bezpłatna?

Tak — pełny tekst „Potoki” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C Academy, przejdź na CoddyKit PRO. Kurs C Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Potoki”?

Komunikacja rodzic–dziecko Ćwiczysz C Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C Academy?

Nie wymagamy żadnego doświadczenia. C Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Potoki”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C Academy?

Tak. Każda lekcja C Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Potoki
  2. Pamięć współdzielona
  3. Kolejki komunikatów
  4. Sygnały
← Powrót do C Academy