簡體   English   中英

為什么父/子進程中的對象具有相同的地址?

[英]Why do objects in parent/child processes have identical addresses?

我對以下代碼有兩個問題:

守則

#include <unistd.h>
#include <semaphore.h>
#include <iostream>

int main(int argc, char **argv)
{
    sem_t sem;
    int var = 0;

    /* create, initialize semaphore */
    if( sem_init(&sem,1,1) < 0)
    {
        perror("semaphore initilization");
        exit(0);
    }

    int pid = fork();
    static const size_t loopLen = 5;
    if (0 == pid)
    { /* child process */
        for (size_t i = 0; i < loopLen; ++i)
        {
            sem_wait(&sem);
            std::string str("Child");
            std::cout << str << " process: &var(" << (void*)(&var) << ") var(" << var++ << ") &sem(" << (void*)(&sem) << ")" << std::endl;
            sem_post(&sem);
        }
    }
    else
    { /* parent process */
        for (size_t i = 0; i < loopLen; ++i)
        {
            sem_wait(&sem);
            std::string str("Parent");
            std::cout << str << " process: &var(" << (void*)(&var) << ") var(" << var++ << ") &sem(" << (void*)(&sem) << ")" << std::endl;
            sem_post(&sem);
        }
    }
}

輸出

Parent process: &var(0xffffcbdc) var(0) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(0) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(1) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(1) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(2) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(2) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(3) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(3) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(4) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(4) &sem(0xffffcbe0)

問題

從父進程和子進程打印時,為什么varsem的地址相同? 我知道子進程獲取父內存空間內容的副本 ,但我認為進程有獨立且不同的地址空間,因此沒有變量會在同一個內存位置 - 但這個輸出似乎表明不是這樣。

問題

這段代碼實際上是在同步兩個進程嗎? 我持懷疑態度。 雖然我用pshared標志非零調用sem_init ,但它似乎再次是子進程應該獲取信號量的副本 我沒有看到sem在父進程和子進程之間“共享”的機制:信號量沒有命名,我不明白在父進程和子進程之間如何共享信號量。 我懷疑每個進程只是獲取並釋放自己的信號量“副本”,但我不確定。

謝謝。

Linux使用“ 寫時復制 ”的習慣用法,這意味着在調用fork() ,父進程的內存不會立即被復制(作為單獨的副本)。 只有當子進程嘗試將任何數據寫入內存時,才會發生該副本。

理解“實際”內存地址(即物理內存中的地址)與映射地址(應用程序的內存空間中的地址)之間的區別也很重要。 兩個應用程序中的兩個指針可能具有相同的值(虛擬地址),但這並不意味着它們確實指向相同的物理位置: 內存映射

關於地址,這是因為子進程最初是父進程的完全重復 精確復制包括(虛擬)內存映射。 閱讀fork手冊頁以獲取更多信息。

關於信號量,如果你閱讀sem_init手冊頁,你會看到

如果pshared非零,那么信號量在進程之間共享,並且應該位於共享內存的區域中

這個位於共享內存中的位置由你來處理,但這並不是你自動完成的。

除了SingerOfTheFall的答案之外,我想補充說fork(2)制作了父進程的精確副本 - 相同的內存映射,相同的信號掩碼,相同的文件描述符表 - 所以你實際上得到了你的進程的真實副本。

這些進程確實有不同的地址空間,但是為了理解為什么修改其中一個進程不會影響另一個進程,你應該記住虛擬和物理地址之間的區別以及所有進程(甚至是amd64上的內核)在虛擬地址空間中執行。

長話短說 - 簡而言之,CPU中有對應表(稱為頁表),每當您嘗試訪問給定地址時,CPU都會查找有問題地址的實際物理地址。 內核為每個進程填充頁表,並為每個進程提供相同的地址(如果未啟用ASLR)。

我無法確定為什么父母和孩子之間共享信號量,但如果你的初始化是正確的,那么它就不應該從外部世界獲得。

參看

https://en.wikipedia.org/wiki/Virtual_address_space

https://en.wikipedia.org/wiki/Page_table

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM