trùng lặp / trùng lặp - tại sao tôi cần sao chép bộ mô tả tệp?


85

Tôi đang cố gắng hiểu việc sử dụng dup2dup.

Từ trang người đàn ông:

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

Tại sao tôi cần cuộc gọi hệ thống đó? việc sử dụng sao chép bộ mô tả tệp là gì?

Nếu tôi có trình mô tả tệp, tại sao tôi muốn tạo một bản sao của nó?

Tôi đánh giá cao nếu bạn có thể giải thích và cho tôi một ví dụ về nơi dup2/ dupcần thiết.

Cảm ơn


Làm thế nào bạn sẽ triển khai chức năng đường ống của shell mà không có duphoặc dup2? Bạn cần phải gọi pipe(2)và sau đó có một trong những file descriptor dup-ed để ví dụSTDIN_FILENO
Basile Starynkevitch

Câu trả lời:


46

Lệnh lặp hệ thống sao chép một bộ mô tả tệp hiện có, trả về một bộ mô tả mới tham chiếu đến cùng một đối tượng I / O bên dưới.

Dup cho phép trình bao thực hiện các lệnh như sau:

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

2> & 1 yêu cầu trình bao cung cấp cho lệnh một bộ mô tả tệp 2 là bản sao của bộ mô tả 1. (tức là stderr & stdout trỏ đến cùng một fd).
Bây giờ thông báo lỗi khi gọi ls trên tệp không tồn tại và đầu ra chính xác của ls trên tệp hiện có hiển thị trong tệp tmp1 .

Mã ví dụ sau chạy chương trình wc với đầu vào tiêu chuẩn được kết nối với đầu đọc của một đường ống.

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

Con đưa phần cuối đọc vào bộ mô tả tệp 0, đóng tệp de tập lệnh bằng p và thực thi wc. Khi wc đọc từ đầu vào chuẩn của nó, nó sẽ đọc từ đường ống.
Đây là cách các đường ống được triển khai bằng cách sử dụng lặp lại, tốt rằng một lần sử dụng lặp lại bây giờ bạn sử dụng đường ống để xây dựng một thứ khác, đó là vẻ đẹp của các lệnh gọi hệ thống, bạn xây dựng thứ này đến thứ khác bằng cách sử dụng các công cụ đã có sẵn, những công cụ này được xây dựng bằng cách sử dụng thứ gì đó khác, v.v. Ở cuối các lệnh gọi hệ thống là công cụ cơ bản nhất mà bạn nhận được trong hạt nhân

Chúc mừng :)


1
Vì vậy, dupcó hữu ích cho người gọi chứ không phải lschính chương trình? Có lợi ích gì khi dupsử dụng trong chương trình như chính ls nếu đã có quyền truy cập vào tệp không? Ví dụ ở đây, lsghi các lỗi 2được mã hóa cứng, vì vậy tôi có một cách để xử lý nó với tư cách là người tiêu dùng ls. Tôi nghĩ rằng đó là một điểm tinh tế không?
Nishant

2
Chương trình ví dụ của bạn dường như có một lỗi; bạn đang gọi dup(p[STDIN])nhưng sau đó bỏ qua kết quả. Bạn có ý định sử dụng dup2(p[STDIN], 0)?
Quuxplusone

1
@Quuxplusone duptrả về "bộ mô tả được đánh số thấp nhất hiện không được quy trình sử dụng." Vì fd 0 vừa được đóng, dupnên trả về 0. dup2rõ ràng về fd nào nên được sử dụng, thay vì chỉ sử dụng fd miễn phí thấp nhất, vì vậy tôi muốn điều đó hơn.
Wodin

@Wodin: Ah, tôi cá là bạn nói đúng về những gì OP đang nghĩ. Tôi cũng đúng, mặc dù vậy, "vừa mới đóng" là tương đối và mã của OP có thể bị hỏng khi có, ví dụ, các luồng đồng thời có thể cũng đang mở tệp?
Quuxplusone

@Quuxplusone Tôi nghi ngờ bạn đúng, nhưng không biết chắc chắn. Nhưng trong trường hợp đó, bạn sẽ gặp những vấn đề khác. Nếu bạn đóng stdin vì bạn muốn đọc từ một nơi khác và sau đó một luồng khác mở một tệp trước khi bạn làm, nó sẽ nhận được fd 0. Nếu sau đó bạn sử dụng Dup2, nó sẽ đóng fd mà luồng khác đã mở, vì vậy luồng khác bây giờ sẽ đọc (và ghi vào?) tệp bạn mở. Dù sao, nếu tôi nhớ không nhầm thì bạn không nên gọi exec*từ một quy trình đa luồng. Nhưng tôi không có luồng chuyên gia :)
Wodin

18

Một lý do khác để sao chép bộ mô tả tệp là sử dụng nó với fdopen. fcloseđóng trình mô tả tệp đã được chuyển đến fdopen, vì vậy nếu bạn không muốn đóng trình mô tả tệp gốc, bạn phải sao chép nó với duptrước.


fdopen()Có vẻ như không sao chép một bộ mô tả tệp, nó chỉ tạo bộ đệm trong không gian người dùng.
Eric Wang

3
Bạn đã đọc sai câu trả lời của tôi. Vấn đề là bạn có thể muốn dupfd trước khi chuyển nó đến fdopenfclosenó sẽ đóng nó.
R .. GitHub NGỪNG TRỢ GIÚP TỪ

1
@ theferrit32: Nếu bạn cấp phát một FILExử lý để truy cập tệp đang mở đã có từ trước thông qua các giao diện stdio, bạn cần gọi fcloseđể phân bổ FILExử lý đó . Nếu bạn muốn tiếp tục sử dụng tệp đang mở bên dưới hoặc nếu kiến ​​trúc phần mềm của bạn giống như mã "chủ sở hữu" ban đầu cho bộ mô tả tệp close, thì việc fcloseđóng bộ mô tả tệp bên dưới mà bạn đã cung cấp fdopenlà một vấn đề. Bạn có thể tránh sự cố này bằng cách sử dụng dupđể tạo một bộ mô tả tệp mới cho cùng một tệp đang mở để chuyển tới fdopen, để fclosekhông đóng tệp gốc.
R .. GitHub NGỪNG TRỢ GIÚP ICE

1
Vấn đề là fdopen () chuyển quyền sở hữu fd sang FILE, thay vì sao chép nó. Đó là điều mà người dùng nên lưu ý. Người tiêu dùng cần giữ lại một fdtay cầm có thể sử dụng ngoài FILEđối tượng phải sao chép fd. Đó là tất cả.
Conrad Meyer

1
@ConradMeyer: Vâng, đó là một cách nói rất hay, với một lưu ý rằng không có thao tác "chuyển quyền sở hữu" nào FILEsau khi bạn chuyển quyền sở hữu sang nó.
R .. GitHub NGỪNG TRỢ GIÚP ICE

4

Dup được sử dụng để có thể chuyển hướng đầu ra từ một quá trình.

Ví dụ: nếu bạn muốn lưu đầu ra từ một quy trình, bạn sao chép đầu ra (fd = 1), bạn chuyển hướng fd đã sao chép thành một tệp, sau đó phân nhánh và thực hiện quy trình và khi quá trình kết thúc, bạn chuyển hướng lại đã lưu fd vào đầu ra.


4

Xin lưu ý một số điểm liên quan đến trùng lặp / trùng lặp2

Dup / Dup2 - Về mặt kỹ thuật, mục đích là chia sẻ một Mục nhập bảng Tệp bên trong một quy trình duy nhất bằng các tay cầm khác nhau. (Nếu chúng ta đang phân tách bộ mô tả được sao chép theo mặc định trong tiến trình con và mục nhập bảng tệp cũng được chia sẻ).

Điều đó có nghĩa là chúng ta có thể có nhiều hơn một bộ mô tả tệp có các thuộc tínhthể khác nhau cho một mục nhập bảng tệp đang mở bằng cách sử dụng hàm lặp / lặp lại.

(Mặc dù hiện tại chỉ có cờ FD_CLOEXEC là thuộc tính duy nhất cho bộ mô tả tệp).

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

Sự khác biệt là (đối với cuối cùng) - Ngoài một số giá trị errno beteen Dup2 và fcntl đóng theo sau là fcntl có thể làm tăng điều kiện chủng tộc vì có liên quan đến hai lệnh gọi hàm.

Chi tiết có thể được kiểm tra từ http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html

Ví dụ về việc sử dụng -

Một ví dụ thú vị trong khi thực hiện kiểm soát công việc trong một trình bao, nơi có thể thấy việc sử dụng lặp / lặp lại2 .. trong liên kết bên dưới

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.