Sự khác biệt giữa fork () và vfork () là gì?


13

Tôi muốn hiểu chi tiết về sự khác biệt giữa fork () và vfork (). Tôi đã không thể tiêu hóa hoàn toàn trang người đàn ông.

Tôi cũng muốn làm rõ một trong những đồng nghiệp của tôi nhận xét " Trong Linux hiện tại, không có vfork (), ngay cả khi bạn gọi nó, nó sẽ gọi fork () trong nội bộ ."

Câu trả lời:


24

Trang man thường là tài liệu tham khảo ngắn gọn. Wikipedia là một nơi tốt hơn để chuyển sang giải thích khái niệm.

Fork nhân đôi một quy trình: nó tạo ra một quy trình con gần giống với quy trình cha (sự khác biệt rõ ràng nhất là quy trình mới có ID quy trình khác nhau). Cụ thể, fork (về mặt khái niệm) phải sao chép tất cả bộ nhớ của tiến trình cha.

Vì điều này khá tốn kém, vfork đã được phát minh để xử lý một trường hợp đặc biệt phổ biến trong đó bản sao là không cần thiết. Thông thường, điều đầu tiên mà tiến trình con thực hiện là tải một hình ảnh chương trình mới, vì vậy đây là điều xảy ra:

if (fork()) {
    # parent process …
} else {
    # child process (with a new copy of the process memory)
    execve("/bin/sh", …);  # discard the process memory
}

Cuộc execvegọi tải một chương trình thực thi mới và điều này thay thế mã và bộ nhớ dữ liệu của quy trình bằng mã của tệp thực thi mới và bộ nhớ dữ liệu mới. Vì vậy, toàn bộ bản sao bộ nhớ được tạo bởi forktất cả là không có gì.

Do đó, vforkcuộc gọi đã được phát minh. Nó không tạo ra một bản sao của bộ nhớ. Do đó vforkrất rẻ, nhưng thật khó để sử dụng vì bạn phải đảm bảo rằng bạn không truy cập vào bất kỳ ngăn xếp hoặc không gian đống nào của quy trình trong quy trình con. Lưu ý rằng ngay cả việc đọc có thể là một vấn đề, bởi vì quá trình cha tiếp tục thực thi. Ví dụ: mã này bị hỏng (nó có thể hoạt động hoặc không hoạt động tùy thuộc vào việc đứa trẻ hoặc cha mẹ có được một lát thời gian trước hay không):

if (vfork()) {
    # parent process
    cmd = NULL; # modify the only copy of cmd
} else {
    # child process
    execve("/bin/sh", "sh", "-c", cmd, (char*)NULL);  # read the only copy of cmd
}

Kể từ khi phát minh ra vfork, tối ưu hóa tốt hơn đã được phát minh. Hầu hết các hệ thống hiện đại, bao gồm cả Linux, sử dụng một hình thức sao chép khi ghi , trong đó các trang trong bộ nhớ quy trình không được sao chép tại thời điểm forkcuộc gọi, nhưng sau đó khi cha mẹ hoặc con lần đầu tiên ghi vào trang. Nghĩa là, mỗi trang bắt đầu như được chia sẻ và vẫn được chia sẻ cho đến khi quá trình ghi vào trang đó; quá trình viết sẽ nhận được một trang vật lý mới (có cùng địa chỉ ảo). Copy-on-write làm cho vfork hầu như vô dụng, vì forksẽ không tạo ra bất kỳ bản sao nào trong trường hợp vforkcó thể sử dụng được.

Linux giữ lại vfork. Cuộc forkgọi hệ thống vẫn phải tạo một bản sao của bảng bộ nhớ ảo của quy trình, ngay cả khi nó không sao chép bộ nhớ thực; vforkthậm chí không cần phải làm điều này. Sự cải thiện hiệu suất là không đáng kể trong hầu hết các ứng dụng.


1
Cảm ơn vì câu trả lời tuyệt vời này .. Trong khi thực hiện fork (), dù sao đi nữa, đứa trẻ sẽ nhận được ID tiến trình mới và không gian ảo được liên kết của nó, vậy tại sao nó vẫn phải tạo một bản sao của bảng bộ nhớ ảo của quy trình? Tôi không rõ ràng trong phần đó.
Sen

@Sen: forkcần tạo một ánh xạ bộ nhớ ảo riêng để các bản sao sao chép tiếp theo chỉ ảnh hưởng đến một trong hai quy trình.
Gilles 'SO- đừng trở nên xấu xa'

Bạn có chắc chắn rằng quá trình cha mẹ đang chạy?
qbolec

2

Các tòa nhà fork()vfork()tòa nhà là khác nhau.

Tòa nhà cao tầng fork()tạo ra hai quá trình giống hệt nhau với bộ nhớ riêng biệt. Tòa nhà cao tầng vfork()tạo ra hai quá trình chia sẻ cùng một bộ nhớ.

Với vfork()cha mẹ sẽ chờ con chấm dứt. Cha mẹ kế thừa từ các biến mà chương trình đang chia sẻ. Vì vậy, sau khi đứa trẻ được gọi, tất cả các biến được sửa đổi bên trong đứa trẻ vẫn sẽ được sửa đổi bên trong cha mẹ.

Để biết thêm thông tin bấm vào đây

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.