Próbuję zrozumieć użycie dup2
i dup
.
Ze strony podręcznika:
DESCRIPTION
dup and dup2 create a copy of the file descriptor oldfd.
After successful return of dup or dup2, the old and new descriptors may
be used interchangeably. They share locks, file position pointers and
flags; for example, if the file position is modified by using lseek on
one of the descriptors, the position is also changed for the other.
The two descriptors do not share the close-on-exec flag, however.
dup uses the lowest-numbered unused descriptor for the new descriptor.
dup2 makes newfd be the copy of oldfd, closing newfd first if necessary.
RETURN VALUE
dup and dup2 return the new descriptor, or -1 if an error occurred
(in which case, errno is set appropriately).
Po co mi to wywołanie systemowe? jaki jest pożytek z powielania deskryptora pliku?
Jeśli mam deskryptor pliku, dlaczego miałbym chcieć zrobić jego kopię?
Byłbym wdzięczny, gdybyś mógł wyjaśnić i podać przykład, gdzie dup2
/ dup
jest potrzebny.
Dzięki
dup
lubdup2
? Trzeba zadzwonić,pipe(2)
a potem mieć jeden z deskryptorów plikówdup
STDIN_FILENO
Odpowiedzi:
Wywołanie systemowe dup powiela istniejący deskryptor pliku, zwracając nowy, który odwołuje się do tego samego bazowego obiektu we / wy.
Dup pozwala powłokom na implementację takich poleceń:
ls existing-file non-existing-file > tmp1 2>&1
2> & 1 mówi powłoce, aby przekazała poleceniu deskryptor pliku 2, który jest duplikatem deskryptora 1. (tj. Stderr i stdout wskazują na to samo fd).
Teraz komunikat o błędzie dotyczący wywołania ls na nieistniejącym pliku i prawidłowe wyjście ls w istniejącym pliku pojawia się w pliku tmp1 .
Poniższy przykładowy kod uruchamia program wc ze standardowym wejściem podłączonym do końca odczytu potoku.
int p[2]; char *argv[2]; argv[0] = "wc"; argv[1] = 0; pipe(p); if(fork() == 0) { close(STDIN); //CHILD CLOSING stdin dup(p[STDIN]); // copies the fd of read end of pipe into its fd i.e 0 (STDIN) close(p[STDIN]); close(p[STDOUT]); exec("/bin/wc", argv); } else { write(p[STDOUT], "hello world\n", 12); close(p[STDIN]); close(p[STDOUT]); }
Dziecko kopiuje koniec odczytu do deskryptora pliku 0, zamyka plik de scriptors w p i wykonuje wc. Kiedy wc czyta ze swojego standardowego wejścia, czyta z potoku.
Oto jak potoki są implementowane przy użyciu dup, cóż, jedno użycie dup teraz używasz potoku do zbudowania czegoś innego, to jest piękno wywołań systemowych, budujesz jedną rzecz po drugiej używając narzędzi, które już istnieją, te narzędzia zostały zbudowane ponownie za pomocą coś jeszcze tak dalej… Ostatecznie wywołania systemowe są najbardziej podstawowymi narzędziami, jakie dostajesz w jądrze
Twoje zdrowie :)
źródło
dup
jest to pomocne dla dzwoniącego, a nie dlals
samego programu? Czy jest jakaś korzyść zdup
używania w programie takim jak sam ls, jeśli ma już dostęp do pliku? Tutaj na przykładls
zapisuje błędy, do2
których jest zakodowane na stałe, więc jako konsument mam sposób, aby je zastąpićls
. Myślę, że to subtelna kwestia, nie?dup(p[STDIN])
ale odrzucasz wynik. Czy chciałeś użyćdup2(p[STDIN], 0)
?dup
zwraca „deskryptor o najniższym numerze, który nie jest obecnie używany przez proces”. Ponieważ fd 0 właśnie się zamknęło,dup
powinno zwrócić 0.dup2
jest jasne, którego fd powinno być użyte, zamiast używać tylko najniższego wolnego fd, więc wolałbym to.exec*
z procesu wielowątkowego. Ale ja nie jestem ekspertem od wątków :)Innym powodem duplikowania deskryptora pliku jest używanie go z rozszerzeniem
fdopen
.fclose
zamyka deskryptor pliku, do którego został przekazanyfdopen
, więc jeśli nie chcesz, aby oryginalny deskryptor pliku był zamykany, musiszdup
najpierw zduplikować go za pomocą .źródło
fdopen()
wydaje się, że nie powiela deskryptora pliku, po prostu tworzy bufor w przestrzeni użytkownika.dup
fd przed przekazaniem go do,fdopen
ponieważfclose
zamknie go.FILE
uchwyt, aby uzyskać dostęp do istniejącego wcześniej otwartego pliku przez interfejsy stdio, musisz wywołać,fclose
aby zwolnić tenFILE
uchwyt. Jeśli chcesz nadal używać podstawowego otwartego pliku lub jeśli architektura twojego oprogramowania jest taka, że oryginalny kod „właściciela” deskryptora pliku będzieclose
to robił, fakt, żefclose
również zamyka podstawowy deskryptor pliku, który przekazałeś,fdopen
jest problemem. Możesz uniknąć tego problemu, używającdup
do utworzenia nowego deskryptora pliku dla tego samego otwartego pliku, do którego ma zostać przekazanyfdopen
, tak abyfclose
nie zamykał oryginalnego.FILE
, zamiast go kopiować . To jest coś, o czym użytkownicy powinni wiedzieć. Konsumenci, którzy muszą zachowaćfd
uchwyt użyteczny opróczFILE
obiektu, muszą zduplikować rozszerzeniefd
. To wszystko.FILE
przeniesienia własności.dup służy do przekierowania wyjścia z procesu.
Na przykład, jeśli chcesz zapisać dane wyjściowe z procesu, duplikujesz dane wyjściowe (fd = 1), przekierowujesz zduplikowany plik fd do pliku, następnie forkuj i wykonuj proces, a po zakończeniu procesu przekierowujesz ponownie zapisano fd do wyjścia.
źródło
Proszę zwrócić uwagę na kilka punktów związanych z dup / dup2
dup / dup2 - Technicznie celem jest współdzielenie jednego wpisu tabeli plików w ramach jednego procesu pomocą różnych uchwytów. (Jeśli rozwidlamy deskryptor jest domyślnie powielany w procesie potomnym, a wpis w tablicy plików jest również współdzielony).
Oznacza to, że możemy mieć więcej niż jeden deskryptor pliku mający prawdopodobnie różne atrybuty dla jednego wpisu tablicy otwartego pliku przy użyciu funkcji dup / dup2.
(Chociaż wydaje się, że obecnie jedyna flaga FD_CLOEXEC jest jedynym atrybutem deskryptora pliku).
http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html
dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0); dup2(fildes, fildes2); is equivalent to close(fildes2); fcntl(fildes, F_DUPFD, fildes2);
Różnice są (ostatnie) - oprócz pewnej wartości errno między wartościami errno beteen dup2 i fcntl close, po których następuje fcntl, mogą podnieść warunki wyścigu, ponieważ w grę wchodzą dwa wywołania funkcji.
Szczegóły można sprawdzić pod adresem http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
Przykład użycia -
Ciekawy przykład implementacji kontroli zadań w powłoce, gdzie użycie dup / dup2 można zobaczyć .. w linku poniżej
http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs
źródło