2014-02-25 2 views
1

제 질문은 기술적 인 문제보다 철학적 인 것입니다.C로 다중 처리 응용 프로그램을위한 아키텍처 : fork 또는 fork + exec

목표는 하나의 "마스터"프로세스와 N 개의 "작업자"프로세스가있는 다중 프로세스 (멀티 스레드가 아닌) 프로그램을 작성하는 것입니다. 프로그램은 nginx와 같이 Linux 전용 비동기 이벤트 기반 웹 서버입니다. 따라서 주된 문제는 "작업자"프로세스를 생성하는 방법입니다.

리눅스 세계에는 두 가지 방법이 있습니다.

1). fork()

2). fork() + exec*() 가족

각 방법에 대한 간략한 설명과 각각의 혼란 스러움.

첫 번째 방법은 forked 프로세스에 부모 메모리의 복사본 (... 쓰기, 알아요. 스택 및 힙. 결론적으로 말하면, fork 후에 i ... hmm ... "clear memory", 예를 들어, 신호 처리기, 소켓 연결 및 부모로부터 상속받은 기타 끔찍한 것들을 사용하지 않도록 설정해야합니다. 왜냐하면 자식은 의도하지 않은 많은 데이터를 가지고 있기 때문입니다. - 캡슐화를 깨고 많은 부작용이 가능합니다.

이 경우 일반적인 방법은 포크 프로세스에서 무한 루프를 실행하여 일부 데이터를 처리하고 fork() 전후의 부모와 자식 간의 통신 채널 생성을위한 소켓 쌍, 파이프 또는 공유 메모리로 마술을합니다. 소켓 설명자가 다시 열리기 때문에 자식으로 사용하고 동일한 소켓을 부모로 사용했습니다.

또한 nginx-way입니다. 하나의 실행 가능한 이진 파일을 가지고 있으며 자식 프로세스를 생성하기 위해 fork()을 사용합니다.

두 번째 방법은 첫 번째 방법과 비슷하지만 실행 외부 이진의 경우 fork() 이후에 하위 프로세스에서 exec*() 함수 사용과 차이가 있습니다. 한 가지 중요한 점은 exec*()은 현재 (분기 된) 프로세스 메모리, 자동 클리어 스택, 힙 (heap)에서 이진수를로드하고 다른 모든 불쾌한 작업을 수행하므로 fork가 부모 메모리 또는 다른 휴지통을 복사하지 않고 프로그램의 명확한 새 인스턴스처럼 보일 것입니다.

부모와 자식 간의 통신 설정에 또 다른 문제가 있습니다. exec*() 이후 forked 프로세스가 부모로부터 상속 된 모든 데이터를 제거하기 때문에 부모와 자식 사이에 소켓 쌍을 생성해야합니다. 예를 들어, 부모 및 대기 자식 연결에 추가 청취 소켓 (도메인 또는 다른 포트)을 만들고 자식은 초기화 후에 부모에 연결해야합니다.

첫 번째 방법은 간단하지만 많은 분명한 부작용과 휴지통이있는 명확한 프로세스는 아니며 상위 메모리 복사본 일 뿐이며 혼란 스럽습니다. 분기 된 프로세스에는 많은 종속성이 있습니다. 상위 코드. 두 번째 방법은 두 개의 바이너리를 지원하는 데 더 많은 시간을 필요로하며 단일 파일 솔루션처럼 우아하지는 않습니다. 어쩌면, 최선의 방법은 fork()을 프로세스 생성에 사용하고 exec*() 호출없이 메모리를 지우는 것이지만 두 번째 단계에 대한 해결책은 찾을 수 없습니다.

결론적으로 nginx와 같은 하나의 파일 실행 파일을 만들고 fork()을 사용하거나 "서버"와 "작업자"가있는 두 개의 개별 파일을 만들고 사용하는 방법을 결정하는 데 도움이 필요합니다. fork() + exec*(worker) N 시간 "서버"에서, 그리고 각 방법에 대한 장단점을 알고 싶다면 어쩌면 뭔가 놓쳤을 수 있습니다.

+0

내 돈을 위해, 이것은 생각할 필요가 없습니다. 옵션 1은 이것을 수행하는 표준 방법이며, 나는 당신이 얼마나 어려운지에 대해 너 자신을 시끄럽게 생각한다고 생각한다. 옵션 2는 실제로 아무것도 얻지 못하며 구현하기가 덜 효율적이고 성가시다. – Duck

답변

0

다중 프로세스 솔루션의 경우 두 옵션 (fork 및 fork + exec)은 거의 동일하며 하위 및 상위 프로세스 컨텍스트에 따라 다릅니다. 자식 프로세스가 부모의 텍스트 (바이너리)를 실행하고 부모의 직원 (디스크립터, 신호 등)의 전부 또는 일부가 필요한 경우, fork를 사용하는 기호입니다. 자녀가 새로운 바이너리를 실행해야하고 부모의 직원이 필요로하지 않는 경우 - 포크 + 임원이 훨씬 적합합니다.

pthread 라이브러리에도 좋은 기능이 있습니다. pthread_atfork(). fork 이전과 이후에 호출 될 핸들러를 등록 할 수 있습니다. 이 핸들러는 필요한 모든 작업을 수행 할 수 있습니다 (예 : 파일 설명자 닫기).

0

Linux 프로그래머는 멀티 스레딩 프로세스 기능이 풍부한 라이브러리를 보유하고 있습니다. pthread와 친구들을보세요.

요청 당 처리가 필요한 경우, 포크와 친구가 태어날 때부터 가장 널리 사용되었습니다.

+0

아니요, 요청 당 프로세스가 필요하지 않습니다. 아키텍처는 이벤트 기반이며 반응기 패턴을 사용합니다. pthreads에 대해 알고 있지만 먼저 CPU 코어를 효과적으로 활용하려면 스레드 - 프로세스 용 "컨테이너"를 만들어야합니다. – Alex