2011-08-31 11 views
8

Đây là mã của tôiTại sao địa chỉ của biến của quá trình đứa trẻ và quá trình cha mẹ là giống

int main() 
{ 
    pid_t pid; 
    int y = 3; 
    if ((pid = fork()) <0) 
    return -1;; 

    if(pid == 0) /* child */ 
    { 
    printf(" before: %d %p\n", y, &y); 
    y *= 10; 
    printf("after: %d %p\n", y, &y); 
    } 
    else /* father */ 
    { 
    sleep(1); 
    printf("father: %d %p\n" , y , &y); 

    } 
    return 0; 
} 

Đầu ra của chương trình là như sau:

before: 3 ffbff440 
after: 30 ffbff440 
father: 3 ffbff440 

Câu hỏi của tôi là tại sao là địa chỉ của biến của trẻ và cha mẹ giống nhau nhưng giá trị khác nhau?

Trả lời

21

Vì đó là địa chỉ virtual ảo, không phải địa chỉ thực.

Mỗi quy trình nhận được không gian địa chỉ riêng của mình (ví dụ: hệ thống 32 bit có thể cho phép mỗi quy trình có không gian địa chỉ riêng với dải 4G đầy đủ).

Đơn vị quản lý bộ nhớ sẽ ánh xạ địa chỉ ảo đến địa chỉ vật lý (và xử lý những thứ như lỗi trang nếu đổi trang cần phải được mua lại từ bộ nhớ thứ cấp).

Sơ đồ dưới đây có thể giúp đỡ, từng bộ phận đại diện cho một khối 4K bộ nhớ:

Process A   Physical Memory  Process B 
    +-------+   +-------------+  +-------+ 
0K |  |----> 0K | (shared) | <----|  | 0K 
    +-------+   +-------------+  +-------+ 
4K |  |--+  4K |    | <----|  | 4K 
    +-------+ |  +-------------+  +-------+ 
8K |  | +-> 8K |    |  |  | 8K 
    +-------+   +-------------+  +-------+ 
     |    : : : : : : :   | 
     |    +-------------+   | 
     |   128K |    | <--------+ 
     |    +-------------+ 
     +--------> 132K |    | 
         +-------------+ 

Bạn có thể thấy, trong sơ đồ đó, ngắt kết nối giữa các địa chỉ bộ nhớ ảo và địa chỉ bộ nhớ vật lý (và khả năng cho các quy trình để chia sẻ các khối bộ nhớ). Các địa chỉ bên trái và bên phải là các địa chỉ ảo mà các quy trình nhìn thấy.

Địa chỉ trong khối trung tâm là địa chỉ thực tế thực tế nơi dữ liệu "thực sự" là và MMU xử lý ánh xạ.

Để được giải thích sâu hơn về fork (và exec), bạn cũng có thể muốn xem this answer.

+0

Cũng lưu ý rằng nó phải theo cách này. Nếu địa chỉ của 'y' đã thay đổi, thì bất kỳ con trỏ (địa chỉ) nào được giữ trong các biến hoặc cấu trúc trước khi ngã ba sẽ không còn chính xác nữa sau ngã ba. Điều đó sẽ làm cho ngã ba ít hữu ích hơn, vì quá trình con sẽ không thể truy cập bất kỳ cấu trúc dữ liệu nào (danh sách liên kết, cây) hoặc dữ liệu được phân bổ động từ trước, vì những thứ đó dựa vào con trỏ. Các hệ thống không có bộ nhớ ảo khá nhiều không thể thực hiện ngã ba, thay vào đó bạn nhận được vfork (http://pubs.opengroup.org/onlinepubs/7908799/xsh/vfork.html). –

+0

Về mặt kỹ thuật, bạn có thể sử dụng hai con trỏ vô hướng cung cấp thời gian chạy C của bạn (nói cách khác, một con trỏ là một giá trị đã biết và khi chuyển đổi, bạn di chuyển dữ liệu đến nơi khác con và điều chỉnh giá trị đã biết). Nó sẽ là một kẻ giết người hiệu suất mặc dù. Tôi nghĩ rằng chế độ thực Windows đã làm một cái gì đó tương tự như thế này với khóa và mở khóa bộ nhớ. – paxdiablo

+1

Đủ công bằng, về cơ bản bạn đã mô tả một cách rẻ tiền và vui vẻ (hoặc đắt tiền và khổ sở, tùy thuộc vào cách bạn nhìn vào nó) phần mềm thực hiện bộ nhớ ảo. Trong trường hợp đó, bạn vẫn sẽ thấy những gì người hỏi quan sát, rằng địa chỉ trước và sau khi ngã ba in như cùng một giá trị. Trừ khi trình định dạng in '% p' cũng được thêm vào địa chỉ cơ sở, tôi giả sử :-) –

1

Địa chỉ là 'giống nhau' vì mỗi quy trình có không gian địa chỉ ảo của riêng nó và biến thường sẽ được tải vào cùng một vị trí. Lưu ý rằng đây không phải là địa chỉ vật lý trong bộ nhớ. Cũng lưu ý rằng có các chương trình cố ý chọn ngẫu nhiên vị trí mà tại đó một tiến trình được tải để làm cho nó khó tấn công/hack quá trình. Trong trường hợp đó, địa chỉ sẽ khác.