Tại sao các cơ chế tạo quá trình mặc định ngã ba?


46

Hệ thống UNIX gọi để tạo quy trình, fork (), tạo một quy trình con bằng cách sao chép quy trình cha. Tôi hiểu rằng điều này hầu như luôn được theo sau bởi một lệnh gọi exec () để thay thế không gian bộ nhớ của tiến trình con (bao gồm cả đoạn văn bản). Sao chép không gian bộ nhớ của cha mẹ trong ngã ba () luôn có vẻ lãng phí đối với tôi (mặc dù tôi nhận thấy sự lãng phí có thể được giảm thiểu bằng cách làm cho các phân đoạn bộ nhớ sao chép trên ghi để chỉ con trỏ được sao chép). Dù sao, có ai biết tại sao phương pháp sao chép này là cần thiết để tạo quy trình không?


3
Lưu ý rằng fork(2)trang man trong Linux nói: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Tôi tưởng tượng (nhưng không biết chắc chắn) rằng đây là trường hợp cho các hương vị Unix hiện đại khác.
larsks

4
Bản gốc, PDP-11 Unix thực sự đã sao chép tất cả các byte của một quá trình rẽ nhánh: nhưng nó chỉ có 64Kb thực thi và nhiều nhất là 64Kb dữ liệu, vì vậy nó không phải là một gánh nặng lớn, kể cả vào năm 1975. Tôi sẽ đoán rằng MỌI unix và unix-a-like kể từ khoảng năm 1990 đã có các đoạn văn bản sao chép khi viết, vì vậy tôi thậm chí không chắc tại sao sách và bài báo lại truyền bá "vấn đề hiệu suất với ngã ba" nữa.
Bruce Ediger

Ngày nay, fork được triển khai theo cách tương tự như vfork ( openbsd.org/cgi-bin/ mẹo ). Nó hiệu quả, đừng lo lắng.
Aki

Cũng lưu ý rằng có rất nhiều cách sử dụng mà bạn không thực hiện sau khi rẽ nhánh (hoặc ít nhất, không thực thi ngay lập tức): nghĩ về đường ống và máy chủ web.
jfg956

Bạn có thể điều sẽ là chậm. Nhưng như @cjm nói, hãy nhìn vào giải pháp thay thế Microsoft sử dụng CreatProcess, họ phải triển khai các luồng sớm (có thể là điều duy nhất họ dẫn đến), vì CreatProcess chậm. (Họ cũng cần chủ đề vì selectđã bị hỏng, nhưng đó là một câu chuyện khác).
ctrl-alt-delor

Câu trả lời:


57

Đó là để đơn giản hóa giao diện. Thay thế cho forkexecsẽ là một cái gì đó giống như chức năng CreatProcess của Windows . Lưu ý có bao nhiêu tham số CreateProcess, và nhiều trong số chúng là các cấu trúc với nhiều tham số hơn. Điều này là do mọi thứ bạn có thể muốn kiểm soát về quy trình mới phải được chuyển qua CreateProcess. Trên thực tế, CreateProcesskhông có đủ tham số, vì vậy Microsoft đã phải thêm CreatProcessAsUserCreatProcessWithLogonW .

Với fork/execmô hình, bạn không cần tất cả các tham số đó. Thay vào đó, các thuộc tính nhất định của quá trình được bảo tồn trên exec. Điều này cho phép bạn fork, sau đó thay đổi bất kỳ thuộc tính quy trình nào bạn muốn (sử dụng cùng các chức năng bạn sử dụng bình thường), sau đó exec . Trong Linux, forkkhông có tham số và execvechỉ có 3: chương trình để chạy, dòng lệnh để cung cấp cho nó và môi trường của nó. (Có các execchức năng khác , nhưng chúng chỉ là các hàm bao quanh execveđược cung cấp bởi thư viện C để đơn giản hóa các trường hợp sử dụng phổ biến.)

Nếu bạn muốn bắt đầu một quá trình với một thư mục hiện hành khác nhau: fork, chdir, exec.

Nếu bạn muốn chuyển hướng stdin / stdout : fork, đóng / mở tệp , exec.

Nếu bạn muốn sử dụng công tắc: fork, setuid, exec.

Tất cả những điều này có thể được kết hợp khi cần thiết. Nếu ai đó nghĩ ra một loại thuộc tính quy trình mới, bạn không phải thay đổi forkexec.

Như larsks đã đề cập, hầu hết các Unix hiện đại đều sử dụng copy-on-write, do forkđó không liên quan đến chi phí đáng kể.


16
Giải thích tuyệt vời. "Những người không hiểu UNIX bị kết án để phát minh lại nó, thật tội nghiệp." - Henry Spencer
Kyle Jones

1
Cảm ơn! Bạn có một tài liệu tham khảo, bởi bất kỳ cơ hội?
Ellen Spertus

1
@Aki, không, CreatProcess () thực sự tạo ra một quy trình mới và xây dựng nó từ đầu, không cần giả mạo.
psusi

2
Nhưng phải không có một số tương đương với CreatProcess () ở đâu đó trong Unix? Mặt khác, quá trình đầu tiên được tạo ra như thế nào? Không giống như một vị thần sáng tạo thần thoại, quá trình đầu tiên không thể rẽ nhánh () từ hư vô. ;-)
Steven Thứ Hai

2
@StevenMonday, vâng, nhưng nó nằm trong mã khởi tạo của kernel và không thể truy cập được từ bên ngoài. Nó không cần tất cả các tham số đó vì hầu hết mọi thứ đều được mã hóa cứng. Nó chỉ có thể tạo tiến trình ID 1, còn gọi là quá trình init. Sau đó, các quy trình được tạo ra chỉ bằng cách rẽ.
cjm

5

Để đáp ứng câu trả lời của cjm, Thông số kỹ thuật Unix đơn xác định một chức năng có tên vfork(). Hàm đó hoạt động như ngã ba, ngoại trừ quá trình rẽ nhánh có hành vi không xác định nếu nó làm bất cứ điều gì khác ngoài việc thử gọi hàm exec familly hoặc gọi _exit().

Do đó, việc sử dụng duy nhất với hành vi được xác định là:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Vậy vforklàm gì? Nó là một rẻ tiền fork. Trong các triển khai không có bản sao khi ghi, quá trình kết quả sẽ chia sẻ không gian bộ nhớ với quy trình ban đầu (do đó hành vi không xác định). Trong các triển khai với copy-on-write, vforkđược phép đồng nhất với fork(), vì các triển khai copy-on-write rất nhanh.

Ngoài ra còn có posix_spawnchức năng tùy chọn (và một posix_spawnpchức năng) có thể trực tiếp tạo ra một quy trình mới. (Cũng được phép thực hiện chúng với một cuộc gọi thư viện bằng cách sử dụng forkexec, và một triển khai ví dụ được cung cấp.)

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.