하위 프로세스가 작성된 직후 exec () 또는 exit ()를 호출 할 때 vfork ()를 사용하려는 이유는 무엇입니까?


11

운영 체제 개념과 APUE의 말

vfork ()를 사용하면 부모 프로세스가 일시 중단되고 자식 프로세스는 부모의 주소 공간을 사용합니다. vfork ()는 COW (Copy-On-Write)를 사용하지 않기 때문에 자식 프로세스가 부모 주소 공간의 페이지를 변경하면 변경된 페이지가 다시 시작되면 부모에게 표시됩니다. 따라서 자식 프로세스가 부모의 주소 공간을 수정하지 않도록 vfork ()를주의해서 사용해야합니다.

vfork ()는 자식 프로세스가 생성 직후에 exec () 또는 exit ()를 호출 할 때 사용됩니다.

마지막 문장을 어떻게 이해해야합니까?

vfork()calls exec()에 의해 생성 된 자식 프로세스 exec()가 새 프로그램을로드하여 부모 프로세스의 주소 공간을 수정 하지 않습니까?

으로 vfork()호출 된 하위 프로세스 가 하위 프로세스를 종료 할 때 상위 프로세스의 주소 공간을 수정 exit()하지 exit()않습니까?

나는 리눅스를 선호한다.

감사.

답변:


15

vfork()calls exec()에 의해 생성 된 자식 프로세스 exec()가 새 프로그램을로드하여 부모 프로세스의 주소 공간을 수정 하지 않습니까?

아니요, exec()새 프로그램에 새로운 주소 공간을 제공합니다. 부모 주소 공간은 수정하지 않습니다. 예를 들어, 참조 의 토론 execPOSIX 함수리눅스 execve()맨 페이지를 .

vfork ()에 의해 생성 된 자식 프로세스가 exit ()를 호출 할 때, 자식을 종료 할 때 exit ()가 부모 프로세스의 주소 공간을 수정하지 않습니까?

일반 exit()– 실행중인 프로그램 (라이브러리 포함)에 의해 설치된 종료 후크를 실행합니다. vfork()더 제한적입니다. 따라서, 리눅스, 그것은 의무화 를 사용 _exit()하는 하지 않는 C 라이브러리의 정리 함수를 호출합니다.

vfork()옳은 게 어려웠습니다. POSIX 표준의 현재 버전에서 제거되었으며 posix_spawn()대신 사용해야합니다.

당신이하지 않는 그러나, 정말 당신이 무슨 일을하는지 알고, 당신은해야 하지 하나를 사용 vfork()하거나 posix_spawn(); 좋은 오래된 고집 fork()하고 exec().

위에 링크 된 Linux 맨 페이지는 더 많은 컨텍스트를 제공합니다.

그러나, 낡은 옛날 fork(2) 에는 호출자의 데이터 공간의 완전한 사본을 만들 필요 exec(3)가있을 것입니다. 따라서 BSD는 효율성을 높이기 vfork() 위해 부모 프로세스의 주소 공간을 완전히 복사하지는 않았지만 호출 execve(2)또는 종료가 발생할 때까지 부모의 메모리와 제어 스레드를 빌린 시스템 호출을 도입 했습니다. 자식이 리소스를 사용하는 동안 부모 프로세스가 일시 중단되었습니다. 의 사용은 vfork()신중해야 예를 들어, 상위 공정에서 변형되지 데이터는 레지스터에 유지 된 변수에 의존 알고.


감사. "exec ()는 새로운 프로그램을위한 새로운 주소 공간을 제공합니다." 프로세스의 주소 공간에 프로그램을로드하는 exec ()의 정상적인 동작입니까? 나는 일반적으로 또는 특히 vfork ()를 위해 새로운 주소 공간을 만드는 두 개의 링크에서 찾지 못했습니다.
Tim

1
재미있는 점은 vfork ()가 다른 모든 것에 대해 이기고 있다는 것입니다. 쓰기 가능한 메모리가 기가 바이트 인 경우 fork ()보다 엄청나게 빠릅니다.
Joshua

2
사람들에게 사용하도록 지시하지 마십시오 posix_spawn. 그것은 사용하여 정확한 코드 작성 어렵게 상당히입니다 posix_spawn평범한 구식보다가 fork, 당신이하려고하면, 당신은 당신이 사이에서 수행해야 할 일이 않는 파일 동작 또는 속성이없는의 벽돌 벽으로 실행할 수 있습니다 forkexec. vfork와 같은 효율성을 보장하지는 않으므로 사람들이 해결하고자하는 문제를 해결하지도 않습니다.
zwol

1
@zwol : 그건 정말 나쁜 조언입니다. posix_spawn원하는 기능이 부족할 수도 있지만 (C 또는 inline-on-cmdline 쉘 스크립트로 작성된 중개 도우미 프로그램을 통해이 문제를 해결할 수 있음) 원하는 vfork정의 를 달성하려는 시도 는 위험한 정의되지 않은 동작 을 호출합니다. 에 대한 사양에서는 vfork임의 함수 호출을 통해 자식이 before에 상속 할 상태를 설정할 수 없으며 execve, 그렇게하면 부모의 상태가 손상 될 수 있습니다.
R .. GitHub 중지 지원 얼음

1
@Joshua : 현대적인 구현은 대부분의 조건 posix_spawn에서와 거의 동일하게 수행 vfork됩니다. 차이가있는 것은 정확히 vfork안전하지 않은 경우 인 경향이 있습니다 posix_spawn. exec 이전에 자식에서 실행되는 것을 억제 해야하는 신호 처리기가 설치되어 있습니다.
R .. GitHub 중지 지원 얼음

4

를 호출 vfork()하면 새 프로세스가 작성되고 새 프로세스가 스택을 제외하고 상위 프로세스의 프로세스 이미지를 차용합니다. 자식 프로세스에는 새로운 스택 스타가 부여되지만 return호출 한 함수에서 허용하지 않습니다 vfork().

자식이 실행되는 동안 자식이 부모의 주소 공간을 빌 렸을 때 부모 프로세스가 차단됩니다.

당신이 무엇을하든, 단지 스택에 액세스하는 모든 것은 자식의 개인 스택만을 수정합니다. 그러나 전역 데이터를 수정하면 공통 데이터가 수정되므로 상위 데이터에도 영향을줍니다.

글로벌 데이터를 수정하는 것은 다음과 같습니다.

  • malloc () 또는 free () 호출

  • stdio 사용

  • 신호 설정 수정

  • 호출되는 함수에 로컬하지 않은 변수들을 수정 vfork().

  • ...

호출하면 _exit()(중요, 호출하지 않음 exit()) 자식이 종료되고 부모에게 제어권이 다시 부여됩니다.

exec*()패밀리 에서 함수를 호출하면 새 프로그램 코드, 새 데이터 및 부모의 스택 일부로 새 주소 공간이 작성됩니다 (아래 참조). 준비가되면 자식은 더 이상 자식에서 주소 공간을 빌리지 않고 자체 주소 공간을 사용합니다.

주소 공간이 더 이상 다른 프로세스에서 사용되지 않으므로 제어는 상위에 다시 제공됩니다.

중요 : Linux에서는 실제 vfork()구현 이 없습니다 . 리눅스가 아니라 구현 vfork()쓰기에 복사를 기반으로 fork()개념을 만들기 위해 SunOS의-4.0 1988 년 도입 사용자는 사용하는 것이 생각 vfork()리눅스 그냥 공유 데이터를 설정하고 아이가 전화를하지 않은 상태에서 부모를 일시 중단, _exit()또는 한 exec*()기능.

따라서 리눅스는 실제 vfork()커널에서 자식에 대한 주소 공간 설명을 설정할 필요가 없다는 사실로부터 이익을 얻지 못한다. 결과는 vfork()보다 빠르지 않습니다 fork(). 진짜를 구현하는 시스템에서 vfork(), 그것은보다 빠른 일반적으로 3 배이다 fork()포탄의 성능에 그 사용에 영향 vfork()- ksh93최근의 Bourne Shellcsh.

ed 자녀에게 전화 exit()를 걸어서 vfork()는 안되는 이유는 전화 exit()하기 전에 데이터가 유출되지 않은 경우 stdio 를 플러시하기 때문 vfork()입니다. 이상한 결과가 발생할 수 있습니다.

BTW : posix_spawn()는 위에 구현되어 vfork()있으므로 vfork()OS에서 제거되지 않습니다. 리눅스가 사용하지 않는 것으로 언급 vfork()되었다 posix_spawn().

스택의 경우 문서가 거의 없으며 Solaris 매뉴얼 페이지의 내용은 다음과 같습니다.

 The vfork() and vforkx() functions can normally be used  the
 same  way  as  fork() and forkx(), respectively. The calling
 procedure, however, should not return while running  in  the
 child's  context,  since the eventual return from vfork() or
 vforkx() in the parent would be to a  stack  frame  that  no
 longer  exists. 

따라서 구현은 원하는대로 할 수 있습니다. Solaris 구현은 함수 호출의 스택 프레임에 공유 메모리를 사용합니다 vfork(). 어떤 구현도 부모로부터 스택의 오래된 부분에 대한 액세스 권한을 부여하지 않습니다.


4
GNU C 라이브러리 나 musl C 라이브러리 posix_spawn()는 Linux를 기반으로 구현되지 않습니다 vfork(). 둘 다 위에 구현합니다 __clone().
JdeBP

1
@ JdeBP : 당신은 vfork()바로 전화 알아 clone()? 말 그대로 커널에서 하나의 라이너입니다.
Joshua 8

1
"중요 : Linux에는 실제 vfork () 구현이 없습니다." <-이것은 사실이 아니며 적어도 10 년 동안 사실이 아닙니다. 쉘 벤치 마크가 Linux vforkforkLinux 간의 성능 차이를 관찰하지 않으면 뭔가 잘못되었습니다.
zwol

1
이 답변의 후반부 "중요 : Linux에는 실제 vfork () 구현이 없습니다"로 시작하는 것이 대부분 또는 전체적으로 잘못되었습니다.
R .. GitHub 중지 지원 얼음

1
확인하지 않고 청구하지 마십시오. 현재 Bourne Shell은 vfork를 지원하거나 사용하지 않고 컴파일 할 수 있으므로 Linux의 디버깅 기능이 신뢰할 수있는 결과를 제공 할 수 없다고 생각하더라도 쉘에서 vfork와 함께 구성 호출의 실행 시간을 비교할 수 있습니다. 800 테스트로 구성 스크립트를 사용합니다. Solaris에서 vfork를 사용하는 Bourne Shell은 포크 케이스와 비교하여 총 30 % 적은 시스템 CPU 시간을 필요로합니다. Linux에서 동일한 테스트 결과 시스템 CPU 시간이 10 % 미만입니다. Solaris에서는 많은 컴파일러 호출이 포함되어 있으므로 3 배가 아닙니다.
schily
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.