2011-01-18 3 views
1

fork()를 사용하여 상위 프로세스와 하위 프로세스를 작성했으며 "ptr"이라는 메모리 주소를 공유합니다. 하지만 프로그램의 한 출력으로 인해 혼란 스럽습니다.fork() 시스템 호출에서 혼동 됨

주소 : 1) ptr : 123456 의 주소 주 : 하나의 프로세스가이 주소를 변경하면 동일한 부모와 자식 주소가 동일하므로 변경 사항이 반영되어야합니다. 주소가 동일하기 때문에 다른 너무 프로세스.

2) 상위 : * PTR = 44

3) 아이 * PTR = 33

4) 인쇄 값 : 부모가 여전히 이전 값을 유지한다 :의 printf ("PTR = % d의"* ptr); // 출력 : 여전히 44, exp는 33입니다. 자식이 예상 값 33을 인쇄합니다. printf ("ptr = % d", * ptr); // 인쇄 33 잘

질문 1) 아무도 말해 줄 수있는 값이 어떻게 다른가요? 포인터 주소는 부모와 자식 모두 동일하지만?

질문 2) 나는 부모와 자녀가 동일한 주소를 무료로 볼 수 있으므로 오류가 두 번 주어지는 메모리 누수 도구를 만들고 있습니다. 그러나, 우리가 보는 바와 같이 그것은 두 배의 자유의 경우가 아닙니다. 이 문제를 어떻게 분류합니까? 도구가 부모와 자식에 대해 보는 메모리 주소가 같은 addrerss입니까?

PS : 아래의 코드를 참조하십시오

#include <sys/types.h> 
#include <unistd.h> 
#include <cstdlib> 
int main() 
{ 
int pid, *ptr 
ptr=(int*)malloc(sizeof(int)); 
*ptr=33; // Parent keeps the data as 33, before forking. 

if(pid==0){*ptr=44;} // Child modifies data, which is ignored by parent 

// Now we print the memory address and the value both by child and parent 
    if(pid==0) 
    { 
    printf("Child data: %u\n",*ptr); 
    printf("Child address: %u\n",ptr); 
    } 
    if(pid>0) 
    { 
    printf("Parent data: %u\n",*ptr); 
    printf("Parent address: %u\n",ptr); 
    } 
} 

출력 : 아이 데이터 : 44 아이 주소 : 123456

부모 데이터 : (? 여전히 이전 값을 제공하는 방법) (33) 부모 주소 : 123456 (주소는 어떻게되지만 어린이와 다른 데이터는 어떨까요?)

+2

부모와 자식은'fork()'이후에 독립적입니다. 즉, 서로의 데이터를 볼 수 없습니다. 사용자가 모든 데이터를 공유하도록하려면 스레드 대신 사용하는 것이 좋습니다. – Gabe

+0

질문에 대한 답변 2 : 도구에서 무료로 제공되는 도구는 무엇입니까? 프로세스 컨텍스트 내에서 실행 중이면 하나만 볼 수 있습니다. malloc이 다시 호출되는 한 동일한 주소에 여러 개의 free가 유효합니다! 그래서 주소를 보면 당신을 아주 멀리하지 못할 것입니다 ... –

답변

5
if(pid==0){*ptr=44;} // Child modifies data, which is ignored by parent 
질문 1) 가치가 어떻게 다른가요? 포인터 주소는 부모와 자식 모두 동일하지만?

이것은 전체 아이디어입니다. 그들은 동일한 주소를 가질 수 있지만,이 주소는 virtual입니다. 각 프로세스에는 자체 주소 공간이 있습니다. fork()이하는 일은 새로운 프로세스를 생성하고 가상 메모리 레이아웃을 부모처럼 보이게 만듭니다.

어떻게 작동하는지 몇 가지 그림은 Wikipedia article on page tables 및 유사한 주제를 참조하십시오.

- (롱 옆 다음) -

은 무엇 일반적으로 fork()에서 발생하는 것은 부모와 자녀 모두에게 해당 페이지 테이블이 페이지가 읽기 전용으로 표시되도록 설정되어 있습니다. 어떤 위치에서 쓰기 명령어가 발생하면 커널은 page fault을 얻습니다.이 명령어는 잘못된 메모리 접근에서 CPU가 생성합니다. 커널은 갇힌 프로세스에 새로운 메모리를 할당하고 페이지 테이블을 조작하여 올바른 주소에 매핑하고 이전 버퍼를 새로 할당 된 버퍼에 복사 한 다음 쓰기를 계속하도록합니다. 이를 copy-on-write이라고합니다. 이렇게하면 초기 포크가 빠르게 만들어지며 두 프로세스 중 하나에서 작성되지 않은 페이지의 메모리 소비가 줄어 듭니다.

이전 단락은 모두 포크 프로그래밍 모델의 최적화입니다.유닉스 초기 버전은 그렇게하지 않았다고 말합니다. 전체 프로세스의 전체 메모리 복사본을 작성했습니다. 또한 Cygwin의 fork()이 전체 복사본을 작성한다고 들었습니다.

그러나 가상 주소는 메모리의 실제 주소와 아무 관련이 없습니다. CPU는 이것을 실제 메모리가 어디에 있는지 정의하는 페이지 테이블의 "키"로 사용합니다. 페이지 테이블은 페이지가 유효하지 않다고 말할 수도 있는데,이 경우 커널은 "픽스 업"(쓰기시 복사 수행, 스왑 공간에서 페이지 호출) 등의 작업을 수행하거나 합법적으로 유효하지 않은 포인터 액세스의 경우

2

유닉스 계열 시스템에서 메모리가 어떻게 작동하는지 오해했습니다. 부모와 자식의 메모리는 독립적입니다. 사용자가 통신하도록하려면 explicitly shared memory 또는 IPC를 설정할 수 있습니다.

+0

그것이 독립적이라면 어떻게 주소가 같은 것입니까? – kingsmasher1

+0

@ kingsmasher1 : "가상 메모리"를 읽을 수 있습니다. – ShiDoiSi

+0

가상 메모리 개념을 알고 있습니다. 구체적으로 설명해주십시오. – kingsmasher1

0

메모리를 개별 주소가있는 대형 버퍼라고 생각하더라도 더 많은 것이 있습니다.

위의보기는 실제 메모리에는 충분하지만 최신 프로세서에는 MMU 칩 (메모리 관리 장치)이 포함되어 있습니다.이 칩은 물리적 메모리 페이지를 가상 메모리에 매핑합니다. 가상 메모리는 실행중인 프로그램의 사용을 위해 주어진 시스템에 실제 메모리가 충분하지 않을 때 (가상) 메모리 주소를 디스크 (스왑)에 매핑하는데도 사용됩니다.

사용자 공간 (또는 어셈블러에서 작성된 프로그램)에서 C 프로그램을 실행하는 경우 액세스 할 수있는 항목은 가상 메모리이며 주소는 가상 메모리의 주소입니다. 최신 운영 체제에서 모든 프로세스는 자체 독립 메모리 주소 공간을 가지며 주소 공간은 서로 관련이 없습니다 (모든 프로세스가 시스템의 전체 메모리 공간에 액세스 할 수있는 것처럼). 물론 물리적 메모리에 매핑되지 않은 (또는 디스크로 스왑 된) 일부 가상 메모리 페이지에 대한 프로세스 액세스가 "세그먼트 오류"를 일으킬 수 있습니다.

fork를 사용하여 프로세스를 생성하면 아버지의 메모리 공간이 자식 노드에 복제됩니다 (즉, 두 노드의 동일한 가상 주소에있는 동일한 데이터). 포크 후 프로세스 중 하나에서 메모리가 변경되고 다른 프로세스에서는 메모리가 변경되지 않으면 분기됩니다. 실제 메커니즘은 다소 복잡하며 대개는 copy-on-write입니다. 메모리 페이지에서 수정이 수행 될 때마다이 페이지의 복사본이 수행됩니다. 변경이 없으면 두 프로세스가 동일한 물리적 메모리에서 읽기 위해 액세스 할 수 있습니다 . 자식 프로세스의 부모에서 값을 변경할 때 볼 수있는 것을 설명합니다. 두 프로세스 중 하나가 fork 이전에 놓여 졌거나 fork 후에 변경된 경우 다른 값이 표시됩니다.

프로세스가 서로 통신하게하려면 통신 레이어 (소켓, 파일, 파이프, 공유 메모리 등)를 사용해야합니다. 그리고 공유 메모리를 사용하는 것이 다른 방법들에 비해 특히 간단하다는 점을 믿지 마십시오. 사실이 아닙니다.

그건 그렇고 프로세스와 스레드의 차이점입니다. 모든 프로세스는 스레드가 동일한 메모리 공간을 공유하는 동안 자신의 메모리를가집니다. fork()에 의해 생성 된 프로세스에 대해 사실이라고 생각한 것은 기본적으로 스레드에 해당됩니다.

공유 메모리 공간은 기본적으로 커널 레벨 프로그래밍에 해당되지만 포크는 사용할 수 없습니다.

+0

스왑 된 메모리에 액세스하면 페이지 오류가 발생합니다. 가상 메모리 페이지에 올바른 액세스 권한이없는 경우 세그먼트 화 오류가 발생합니다. – Frank

+0

@ 프랭크 : 기본적으로 그렇습니다. 그러나 신호는 결코 C 프로그램으로 넘어 가지 않습니다. 그것은 디스크에서 데이터를 다시로드하고 보이지 않는 OS에 의해 차단됩니다. segfault는 페이지가 실제 메모리 나 디스크 공간에 매핑되지 않은 경우에만 C 프로그램에 의해 수신됩니다. – kriss

관련 문제