dup2 / dup - навіщо мені дублювати дескриптор файлу?


85

Я намагаюся зрозуміти використання dup2та dup.

Зі сторінки користувача:

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).  

Навіщо мені системний дзвінок? яка користь від дублювання дескриптора файлу?

Якщо у мене є дескриптор файлу, чому я хотів би зробити його копію?

Буду вдячний, якби ви пояснили і навели приклад, де dup2/ dupпотрібно.

Дякую


Як би ви реалізували функціональність трубопроводів оболонок без dupабо dup2? Вам потрібно зателефонувати, pipe(2)а потім мати один із дескрипторів файлів dup-ed до напр.STDIN_FILENO
Basile Starynkevitch

Відповіді:


46

Системний виклик dup дублює існуючий дескриптор файлу, повертаючи новий, який посилається на той самий базовий об'єкт вводу-виводу.

Dup дозволяє оболонкам реалізовувати такі команди:

ls existing-file non-existing-file > tmp1  2>&1

2> & 1 вказує оболонці надати команді дескриптор файлу 2, який є дублікатом дескриптора 1. (тобто stderr & stdout вказують на той самий fd).
Тепер повідомлення про помилку для виклику Ls на неіснуючий файл і правильний вихід Ls на існуючому файл шоу в tmp1 файлі.

Наступний приклад коду запускає програму wc зі стандартним входом, підключеним до кінця зчитування труби.

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]);
}

Дочірній матеріал скидає кінець читання на дескриптор файлу 0, закриває дескриптори файлу в p та виконує wc. Коли wc читає зі свого стандартного входу, він читає з труби.
Ось як труби реалізуються за допомогою dup, ну і одне використання dup зараз ви використовуєте pipe, щоб побудувати щось інше, ось у чому краса системних викликів, ви будуєте одне за іншим за допомогою інструментів, які вже є, ці інструменти були побудовані за допомогою щось інше тощо. Зрештою, системні виклики - це найосновніші інструменти, які ви отримуєте в ядрі

На ура :)


1
Тож dupкорисно для абонента, а не самої lsпрограми? Чи є якась перевага від dupвикористання такої програми, як сама ls, якщо вона вже має доступ до файлу? Ось, наприклад, lsпише помилки, до 2яких жорстко закодовано, тому у мене є спосіб перевиконати його як споживача ls. Я думаю, що це тонкий момент ні?
Нішант

2
Здається, у вашій прикладі програми є помилка; ви телефонуєте, dup(p[STDIN])але потім викидаєте результат. Ви мали намір використовувати dup2(p[STDIN], 0)?
Quuxplusone

1
@Quuxplusone dupповертає "дескриптор із найнижчим номером, який наразі не використовується процесом." Оскільки fd 0 було просто закрито, dupслід повернути 0. dup2Явно вказано, який fd слід використовувати, а не просто використовувати найнижчий вільний fd, тому я б вважав за краще це.
Водін

@Wodin: Ах, впевнений, ти маєш рацію щодо того, про що думав ОП. Однак я також маю рацію, що "щойно закрито" є відносним, і код OP може зламатися за наявності, наприклад, одночасних потоків, які також можуть відкривати файли?
Quuxplusone

@Quuxplusone Я підозрюю, що ти маєш рацію, але не знаєш точно. Але в такому випадку у вас будуть інші проблеми. Якщо ви закриваєте stdin, тому що ви хочете читати з іншого місця, а потім інший потік відкриває файл, перш ніж це зробити, він отримає fd 0. Якщо ви потім використовуєте dup2, він закриє fd, що відкрився інший потік, тому інший потік тепер буде читати (та писати?) файл, який ви відкриваєте. У будь-якому випадку, якщо я добре пам’ятаю, вам не слід дзвонити exec*з багатопотокового процесу. Але я не фахівець з ниток :)
Водін,

18

Ще однією причиною дублювання дескриптора файлу є використання його з fdopen. fcloseзакриває дескриптор файлу, якому було передано fdopen, тому, якщо ви не хочете, щоб оригінальний дескриптор файлу був закритий, вам слід дублювати його dupспочатку.


fdopen()здається, не дублюйте дескриптор файлу, він просто створює буфер в просторі користувача.
Ерік Ван,

3
Ви неправильно прочитали мою відповідь. Справа в тому, що ви можете захотіти до dupfd, перш ніж передати його, fdopenоскільки fcloseзакриє його.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕДІ

1
@ theferrit32: Якщо ви виділите FILEдескриптор для доступу до вже існуючого відкритого файлу через інтерфейси stdio, вам потрібно зателефонувати, fcloseщоб звільнити цей FILEдескриптор. Якщо ви хочете продовжувати використовувати базовий відкритий файл, або якщо ваша архітектура програмного забезпечення така, що оригінальний код "власника" дескриптора файлу дозволить close, той факт, що fcloseтакож закриває базовий дескриптор файлу, якому ви передали, fdopenє проблемою. Цю проблему можна уникнути, використовуючи dupдля створення нового дескриптора файлу той самий відкритий файл, якому потрібно передати fdopen, таким чином, що fcloseне закриває вихідний.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

1
Справа в тому, що fdopen () переміщує право власності на fd FILE, а не копіює його. Це те, про що повинні знати користувачі. Споживачі, яким потрібно зберегти зручну fdручку на додаток до FILEоб'єкта, повинні дублювати файл fd. Це все.
Конрад Мейєр,

1
@ConradMeyer: Так, це дуже хороший спосіб сказати це, зауваживши, що не існує жодної операції з "переміщення права власності" від того, FILEяк ви перенесете право власності на неї.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

4

dup використовується для перенаправлення вихідних даних із процесу.

Наприклад, якщо ви хочете зберегти вихідні дані з процесу, ви продублюєте висновок (fd = 1), ви перенаправляєте продубльований fd у файл, потім форкуєте та виконуєте процес, а коли процес закінчується, ви знову перенаправляєте збережений fd для виводу.


4

Будь ласка, зверніть увагу на деякі моменти, пов'язані з dup / dup2

dup / dup2 - Технічно мета полягає в тому, щоб спільно використовувати один запис таблиці файлів в одному процесі різними ручками. (Якщо ми розгалужуємо, дескриптор дублюється за замовчуванням у дочірньому процесі, і запис таблиці файлів також є спільним).

Це означає, що ми можемо мати більше одного дескриптора файлу, що має, можливо, різні атрибути для одного окремого запису таблиці відкритих файлів за допомогою функції dup / dup2.

(Хоча, здається, наразі лише прапор FD_CLOEXEC є єдиним атрибутом дескриптора файлу).

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);

Відмінності є (для останнього) - Окрім деякого значення errno, дванадцять dup2 і fcntl close, а потім fcntl можуть підвищити умови змагання, оскільки беруть участь два виклики функцій.

Деталі можна перевірити за адресою http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html

Приклад використання -

Один цікавий приклад під час реалізації контролю роботи в оболонці, де використання dup / dup2 можна побачити .. за посиланням нижче

http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.