Làm thế nào để copy-on-write trong fork () xử lý nhiều ngã ba?


23

Theo Wikipedia (có thể sai)

Khi một lệnh gọi hệ thống fork () được phát ra, một bản sao của tất cả các trang tương ứng với tiến trình cha mẹ được tạo ra, được HĐH nạp vào một vị trí bộ nhớ riêng cho tiến trình con. Nhưng điều này là không cần thiết trong một số trường hợp nhất định. Hãy xem xét trường hợp khi một đứa trẻ thực hiện một execcuộc gọi hệ thống "" (được sử dụng để thực hiện bất kỳ tệp thực thi nào từ trong chương trình C) hoặc thoát ra rất nhanh sau đó fork(). Khi đứa trẻ cần thiết chỉ để thực thi một lệnh cho tiến trình cha, không cần sao chép các trang của tiến trình cha, vì execthay thế không gian địa chỉ của tiến trình đã gọi nó bằng lệnh được thực thi.

Trong những trường hợp như vậy, một kỹ thuật gọi là copy-on-write (COW) được sử dụng. Với kỹ thuật này, khi một ngã ba xảy ra, các trang của quy trình cha không được sao chép cho quy trình con. Thay vào đó, các trang được chia sẻ giữa trẻ và quá trình cha mẹ. Bất cứ khi nào một quá trình (cha mẹ hoặc con cái) sửa đổi một trang, một bản sao riêng của trang cụ thể đó được tạo ra cho quá trình đó (cha mẹ hoặc con cái) thực hiện sửa đổi. Quá trình này sau đó sẽ sử dụng trang mới được sao chép thay vì trang được chia sẻ trong tất cả các tài liệu tham khảo trong tương lai. Quá trình khác (quy trình không sửa đổi trang được chia sẻ) tiếp tục sử dụng bản sao gốc của trang (hiện không còn được chia sẻ). Kỹ thuật này được gọi là copy-on-write vì trang được sao chép khi một số tiến trình ghi vào nó.

Có vẻ như khi một trong các quy trình cố gắng ghi vào trang, một bản sao mới của trang sẽ được phân bổ và gán cho quy trình tạo ra lỗi trang. Trang gốc được đánh dấu có thể ghi được sau đó.

Câu hỏi của tôi là: điều gì xảy ra nếu fork()được gọi nhiều lần trước khi bất kỳ quy trình nào thực hiện ghi vào trang chia sẻ?


Wikipedia là đúng trong trường hợp này, chỉ cần cấp cao hơn.
Didi Kohen

1
Có, sao chép trên ghi là lười sao chép, quá trình con sao chép trang khi cố gắng viết nó. Về cơ bản, sau một ngã ba, gần như bộ nhớ của trẻ được chia sẻ với cha mẹ. Tuy nhiên, trước bất kỳ quy trình nào được thực hiện, mọi quy trình con vẫn có một số bộ nhớ riêng, được sửa đổi từ phân bổ của cha mẹ hoặc mới. Điều đó có nghĩa là ngay cả khi không có bất kỳ hành động nào, quá trình con rẽ nhánh có một số bộ nhớ riêng. Chúng tôi có thể xác minh nó với pmap -XX PIDhoặc cat /proc/PID/smap.
where23

Về - "Trang gốc được đánh dấu có thể ghi được sau đó.", Ai sẽ sở hữu nó? Ở đây, quá trình khác, những người đã không thử viết nó?
Adil

Cái này thật đáng yêu. Hãy bắt đầu dạy điều này ở trường mẫu giáo
ed22

Câu trả lời:


18

Không có gì đặc biệt xảy ra. Tất cả các quy trình đang chia sẻ cùng một tập hợp các trang và mỗi trang sẽ có bản sao riêng của mình khi muốn sửa đổi một trang.


Đúng. Vấn đề là, đó là quá trình con đặc biệt, có công việc sao chép nếu nó cố gắng viết vào trang chia sẻ. Cả cha mẹ và những đứa trẻ khác đều không cần biết về sự thay đổi nếu nó được thực hiện một cách chính xác.
Charles Stewart

9
Quá trình con không có gì đặc biệt. Cả hai tiến trình con và cha mẹ đều có cùng một tập hợp các trang chỉ đọc sau khi rẽ nhánh. Đối với các trang này, việc xử lý trang là đối xứng.
jlliagre

3

Hành vi của fork () phụ thuộc vào việc hệ thống * nix có MMU hay không. Trên hệ thống không phải MMU (như PDP-11 đầu tiên), cuộc gọi hệ thống fork () đã sao chép tất cả bộ nhớ của cha mẹ cho mỗi đứa trẻ. Trên hệ thống * nix dựa trên MMU, kernel đánh dấu tất cả các trang không ngăn xếp là R / O và chia sẻ chúng giữa cha mẹ và con. Sau đó, khi một trong hai quá trình ghi vào bất kỳ trang nào, MMU bẫy lại nỗ lực, hạt nhân sau đó phân bổ một trang có thể ghi và cập nhật các bảng trang MMU để trỏ đến trang hiện có thể ghi. Hành vi Copy-on-Write này cung cấp tốc độ vì ban đầu chỉ có một ngăn xếp riêng tư cần được phân bổ và nhân bản cho mỗi tiến trình con.

Nếu bạn thực thi một số mã cha giữa mỗi lệnh gọi fork () thì các tiến trình con kết quả sẽ khác nhau bởi các trang đã bị thay đổi bởi cha mẹ. Mặt khác, nếu cha mẹ chỉ đơn giản thực hiện nhiều lệnh gọi fork (), ví dụ như trong một vòng lặp, thì các tiến trình con sẽ gần như giống hệt nhau. Nếu một biến vòng lặp cục bộ được sử dụng thì nó sẽ khác nhau trong mỗi ngăn xếp của trẻ.


0

Khi hệ thống tạo ra một ngã ba, thông thường (điều này có thể phụ thuộc vào việc triển khai), nó cũng đánh dấu các trang là chỉ đọc và đánh dấu tiến trình cha là chủ của các trang này.
Khi cố gắng ghi vào các trang này, sẽ xảy ra lỗi trang và HĐH tiếp quản, sao chép toàn bộ danh sách các trang hoặc chỉ những trang đã thay đổi (một lần nữa, tùy thuộc vào việc thực hiện), do đó quá trình viết sẽ có một bản sao có thể ghi.
Khi có nhiều tiến trình được phân tách từ cùng một quy trình, khi quy trình "chính" ghi vào bộ nhớ của nó, các quy trình khác sẽ sao chép các trang tương đương của chúng.


hệ thống nào làm điều này? linux sử dụng triển khai sao chép trên ghi
brauliobo

Đó là cách hoạt động của bản sao trên văn bản ...
Didi Kohen

3
@DavidKohen đó không phải là cách hoạt động của copy-on-write trong bất kỳ phiên bản nào mà tôi từng nghe nói đến. Không có quá trình "chính chủ". Nếu bất kỳ quy trình đơn lẻ nào viết các trang được chia sẻ, bản sao của nó sẽ bị chặn ở chế độ riêng tư trong khi tất cả các quy trình khác tiếp tục chia sẻ nó.
Celada

1
Tôi nghĩ David Kohen đúng ở một số điểm. Đây là một cách để thực hiện sao chép trên ghi. Ý chính là với cách đánh dấu này, việc viết lên trang đó sẽ kích hoạt trình xử lý lỗi trang sau đó sẽ thực hiện hành động thích hợp, tức là sao chép trên ghi. Thật không may, chi tiết này (sẽ cụ thể theo hệ thống) hầu như không liên quan đến câu hỏi. Hãy nhớ rằng CoW có hai chiều: một chiều hiển thị cho quy trình và một chiều về cách kernel có thể thực hiện nó.
0xC0000022L
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.