2014-10-23 22 views
6

Đây là loại câu hỏi kỹ thuật, có thể bạn có thể giúp tôi nếu bạn biết về C và UNIX (hoặc có thể nó là một câu hỏi thực sự người mới!)Về con trỏ sau khi fork()

Một câu hỏi nảy ra trong phiên hôm nay analizing một số mã trong khóa học Hệ điều hành của chúng tôi. Chúng tôi đang học những gì nó có nghĩa là "ngã ba" một quá trình trong UNIX, chúng tôi đã biết nó tạo ra một bản sao của quá trình hiện tại song song với nó và họ có phần dữ liệu riêng biệt. Nhưng sau đó tôi nghĩ rằng có thể, nếu người ta tạo ra một biến và một con trỏ trỏ vào nó trước khi làm fork(), vì con trỏ lưu trữ địa chỉ bộ nhớ của biến, người ta có thể cố gắng sửa đổi giá trị của biến đó từ quá trình con bằng cách sử dụng con trỏ đó.

Chúng tôi đã thử một mã tương tự như sau trong lớp:

#include <stdio.h> 
#include <sys/types.h> 
#include <stdlib.h> 

int main(){ 
    int value = 0; 
    int * pointer = &value; 
    int status; 

    pid_t pid; 

    printf("Parent: Initial value is %d\n",value); 

    pid = fork(); 

    switch(pid){ 
    case -1: //Error (maybe?) 
     printf("Fork error, WTF?\n"); 
     exit(-1); 

    case 0: //Child process 
     printf("\tChild: I'll try to change the value\n\tChild: The pointer value is %p\n",pointer); 
     (*pointer) = 1; 
     printf("\tChild: I've set the value to %d\n",(*pointer)); 

     exit(EXIT_SUCCESS); 
     break; 
    } 

    while(pid != wait(&status)); //Wait for the child process 

    printf("Parent: the pointer value is %p\nParent: The value is %d\n",pointer,value); 

    return 0; 
} 

Nếu bạn chạy nó, bạn sẽ nhận được một cái gì đó như thế này:

phụ huynh: Giá trị ban đầu là 0

Trẻ em: Tôi sẽ cố gắng thay đổi giá trị

Con: Giá trị con trỏ là 0x7fff733b0c6c

Trẻ em: tôi đã thiết lập các giá trị cho 1

phụ huynh: giá trị con trỏ là 0x7fff733b0c6c

phụ huynh: Giá trị là 0

Rõ ràng rằng quá trình đứa trẻ không ảnh hưởng đến ở tất cả quy trình gốc. Thành thật mà nói, tôi đã mong đợi một số lỗi "phân đoạn lỗi", vì truy cập vào một địa chỉ bộ nhớ không được phép. Nhưng những gì thực sự đã xảy ra?

Hãy nhớ rằng, tôi không tìm cách để giao tiếp quy trình, đó không phải là vấn đề. Những gì tôi muốn biết là mã đã làm gì. Bên trong quá trình con, thay đổi có thể nhìn thấy, do đó, nó DID một cái gì đó.

Giả thuyết chính của tôi là con trỏ không tuyệt đối với bộ nhớ, chúng có liên quan đến ngăn xếp của quy trình. Nhưng tôi đã không thể tìm thấy câu trả lời (không ai trong lớp biết, và googling tôi chỉ tìm thấy một số câu hỏi về quá trình giao tiếp) vì vậy tôi muốn biết từ bạn, hy vọng ai đó sẽ biết.

Cảm ơn bạn đã dành thời gian đọc!

+0

bạn có thể đặt 'printf (" Parent: giá trị con trỏ là% p \ nGiá trị là% d \ n ", con trỏ, giá trị);' trong trường hợp mặc định của 'switch()' – Haris

+2

http://en.wikipedia.org/wiki/Virtual_memory – Mat

+0

"* Thành thật mà nói, tôi đã mong đợi một số lỗi" phân đoạn lỗi ", vì truy cập vào một địa chỉ bộ nhớ không được phép. *" Điều đó không có ý nghĩa. Hãy suy nghĩ về nó. Mã mà đứa trẻ thực hiện là hoàn toàn hợp pháp. Câu hỏi duy nhất là - nó có hay không ảnh hưởng đến cha mẹ? –

Trả lời

11

Chìa khóa ở đây là khái niệm về không gian địa chỉ ảo.

Bộ vi xử lý hiện đại (Nói gì mới hơn sau đó là 80386) có một đơn vị quản lý bộ nhớ ánh xạ từ một không gian địa chỉ ảo cho đến các trang bộ nhớ vật lý dưới sự kiểm soát của hạt nhân.

Khi hạt nhân thiết lập một quá trình, nó tạo ra một tập hợp các mục bảng trang cho quy trình xác định các trang bộ nhớ vật lý để ánh xạ không gian địa chỉ ảo và nó nằm trong không gian địa chỉ ảo mà chương trình thực hiện.

Về mặt lý thuyết khi bạn ngã ba, các bản kernel các trang trình hiện có để một bộ mới của trang vật lý và thiết lập các bảng trang quy trình mới để như xa như quá trình mới là có liên quan nó xuất hiện để được chạy trong cùng một ảo bố trí bộ nhớ như bản gốc đã có, trong khi thực sự giải quyết bộ nhớ vật lý hoàn toàn khác nhau.

Các chi tiết là tinh tế hơn như không ai muốn lãng phí thời gian sao chép hàng trăm MB dữ liệu trừ khi đó là cần thiết. Khi quá trình gọi fork() hạt nhân thiết lập một tập hợp các mục bảng trang thứ hai (cho quy trình mới), nhưng trỏ chúng vào cùng một trang vật lý như quy trình gốc, sau đó đặt cờ trong cả hai trang để làm cho mmu xem chúng chỉ đọc .....

Ngay sau khi một trong hai quá trình ghi vào một trang, đơn vị quản lý bộ nhớ tạo ra lỗi trang (do mục nhập PTE có cờ chỉ đọc), và xử lý lỗi trang sau đó phân bổ một trang mới từ bộ nhớ vật lý, sao chép dữ liệu, cập nhật mục nhập bảng trang và đặt các trang trở lại để đọc/ghi. Bằng cách này, các trang chỉ thực sự được sao chép lần đầu tiên, một trong hai quá trình cố gắng thực hiện thay đổi đối với một bản sao trên trang viết và bàn tay nhỏ hoàn toàn không được chú ý bởi một trong hai quá trình.

Trân trọng, Dan.

3

Đứa trẻ sửa đổi một con trỏ hoàn toàn hợp pháp trong không gian địa chỉ của nó bởi vì nó là một bản sao của cha mẹ của nó. Không có ảnh hưởng đến phụ huynh vì bộ nhớ không được chia sẻ một cách hợp lý. Mỗi quá trình được đi theo cách riêng của nó sau khi ngã ba.

UNIX có một số cách tạo bộ nhớ dùng chung (trong đó một quá trình có thể sửa đổi bộ nhớ và có sửa đổi được xem bởi một quy trình khác), nhưng fork không phải là một trong số chúng. Và đó là một điều tốt bởi vì nếu không, sự đồng bộ hóa giữa cha và con sẽ gần như không thể.

+0

Nhưng tại sao nó hợp pháp? Đó không phải là địa chỉ bộ nhớ do cha mẹ sở hữu phải không? Giá trị là giống nhau – javierbg

+1

Trẻ không biết hoặc quan tâm đến những gì cha mẹ sở hữu. Có, cha mẹ sở hữu địa chỉ bộ nhớ đó (trong không gian địa chỉ của nó). Đứa trẻ cũng sở hữu địa chỉ bộ nhớ đó (trong không gian địa chỉ của nó). Cha mẹ và đứa trẻ bắt đầu làm bản sao nhưng sau đó có thể đi theo những cách riêng biệt. Các không gian bộ nhớ được phép phân kỳ sau ngã ba, nhưng chúng cũng tương tự như vậy. –

+0

Vì vậy, tôi giả định rằng con trỏ không lưu trữ địa chỉ bộ nhớ tuyệt đối vào bộ nhớ vật lý. Đúng không? – javierbg

4

Về mặt logic, quy trình chỉnh sửa fork() có bản sao độc lập, riêng biệt của nhiều hoặc ít hơn toàn bộ trạng thái của quy trình gốc. Điều đó không thể làm việc nếu con trỏ trong đứa trẻ được gọi là bộ nhớ thuộc về cha mẹ.

Chi tiết về cách một hạt nhân giống UNIX cụ thể làm cho công việc đó có thể thay đổi. Linux thực hiện bộ nhớ của tiến trình con thông qua các trang copy-on-write, điều này làm cho giá trị tương đối rẻ hơn so với các triển khai có thể khác. Trong trường hợp đó, con trỏ của đứa trẻ thực sự trỏ đến bộ nhớ của quá trình cha mẹ, cho đến khi trẻ hoặc cha mẹ cố gắng sửa đổi bộ nhớ đó, tại thời điểm đó một bản sao được tạo cho trẻ sử dụng. Tất cả đều dựa vào hệ thống bộ nhớ ảo cơ bản. Các hệ thống UNIX và UNIX khác có thể và đã thực hiện nó một cách khác nhau.

+0

Tôi không biết nhiều về bộ nhớ ảo tại thời điểm này, vì vậy tôi không biết điều đó. Cảm ơn bạn! – javierbg

Các vấn đề liên quan