[linux] 리눅스에서 쓰레드와 프로세스

최근 리눅스에서 프로세스를 처리하는 데 매우 효율적이며 스레드와 관련된 많은 문제 (예 : 잠금)가 있기 때문에 Linux에서는 스레드 대신 프로세스를 사용하는 것이 거의 항상 좋다고 말하는 사람들이 있습니다. 그러나 스레드가 일부 상황에서 상당히 큰 성능 향상을 가져올 수있는 것처럼 보이기 때문에 의심됩니다.

그래서 내 질문은 스레드와 프로세스가 모두 잘 처리 할 수있는 상황에 처했을 때 프로세스 또는 스레드를 사용해야합니까? 예를 들어, 웹 서버를 작성하는 경우 프로세스 또는 스레드 (또는 조합)를 사용해야합니까?



답변

리눅스는 1-1 스레딩 모델을 사용하는데, 커널과 프로세스와 스레드를 구분하지 않고 모든 것이 실행 가능한 작업입니다. *

리눅스에서 시스템 호출은 clone그중 공유의 구성 수준으로, 작업을 복제합니다 :

  • CLONE_FILES: 사본을 작성하는 대신 동일한 파일 디스크립터 테이블을 공유하십시오.
  • CLONE_PARENT: 새 작업과 이전 작업간에 부모-자식 관계를 설정하지 마십시오 (그렇지 않으면 childs getppid()= parent ‘s getpid())
  • CLONE_VM: COW 사본 을 작성하는 대신 동일한 메모리 공간을 공유하십시오.

fork()호출 clone(이상 공유 )pthread_create()통화 clone(대부분의 공유 ). **

forking pthread_create은 테이블을 복사하고 메모리에 대한 COW 매핑을 생성하기 때문에 ing 보다 약간 더 많은 비용이 들지만 Linux 커널 개발자는 이러한 비용을 최소화하려고 노력했습니다.

동일한 메모리 공간과 다양한 테이블을 공유하는 작업 사이의 전환은 데이터가 이미 캐시에로드되어 있기 때문에 공유하지 않는 것보다 약간 저렴합니다. 그러나 아무 것도 공유하지 않아도 작업을 전환하는 것은 여전히 ​​매우 빠릅니다. 이것은 Linux 커널 개발자가 확인하려고 노력하는 것입니다.

실제로 다중 프로세서 시스템을 사용하는 경우 공유 하지 않는 것이 실제로 성능에 도움이 될 수 있습니다. 각 작업이 다른 프로세서에서 실행중인 경우 공유 메모리를 동기화하는 데 많은 비용이 듭니다.


* 단순화. CLONE_THREAD신호 전달이 공유되도록합니다 ( CLONE_SIGHAND필수, 신호 핸들러 테이블을 공유 함).

** 간체. 이 모두 존재 SYS_fork하고 SYS_clone콜을하지만, 커널의를 sys_forksys_clone같은 주위 모두 매우 얇은 래퍼 do_fork자체가 주위에 얇은 래퍼입니다 기능 copy_process. 예, 용어 process, thread그리고 task리눅스 커널에 오히려 의미로 사용됩니다 …


답변

Linux (실제로 Unix)는 세 번째 옵션을 제공합니다.

옵션 1-프로세스

응용 프로그램의 일부 (또는 모든 부분)를 처리하는 독립 실행 형 실행 파일을 만들고 각 프로세스마다 별도로 호출합니다. 예를 들어, 프로그램은 자체 복사본을 실행하여 작업을 위임합니다.

옵션 2-스레드

단일 스레드로 시작하는 독립형 실행 파일을 작성하고 일부 태스크를 수행하기 위해 추가 스레드를 작성하십시오.

옵션 3-포크

Linux / Unix에서만 사용할 수 있으며 약간 다릅니다. 분기 프로세스는 실제로 자체 주소 공간이있는 자체 프로세스입니다. 자식이 부모 또는 형제 주소 공간 (스레드와 달리)에 영향을주기 위해 (일반적으로) 수행 할 수있는 작업이 없으므로 견고성이 추가됩니다.

그러나 메모리 페이지는 복사되지 않고 기록 중 복사되므로 일반적으로 생각보다 적은 메모리가 사용됩니다.

다음 두 단계로 구성된 웹 서버 프로그램을 고려하십시오.

  1. 구성 및 런타임 데이터 읽기
  2. 페이지 요청 제공

스레드를 사용한 경우 1 단계는 한 번 수행되고 2 단계는 여러 스레드에서 수행됩니다. “전통적인”프로세스를 사용한 경우 각 프로세스에 대해 1 단계와 2 단계를 반복해야하며 구성 및 런타임 데이터를 저장하기위한 메모리가 복제됩니다. fork ()를 사용한 경우 1 단계를 한 번 수행 한 다음 fork ()를 수행하여 런타임 데이터와 구성을 메모리에 그대로두고 그대로 그대로 복사 할 수 있습니다.

따라서 실제로 세 가지 선택이 있습니다.


답변

그것은 많은 요인에 달려 있습니다. 프로세스는 스레드보다 무겁고 시작 및 종료 비용이 높습니다. 프로세스 간 통신 (IPC)도 스레드 간 통신보다 어렵고 느립니다.

반대로 각 프로세스는 자체 가상 주소 공간에서 실행되므로 프로세스는 스레드보다 안전하고 안전합니다. 하나의 프로세스가 충돌하거나 버퍼 오버런이 발생하면 다른 프로세스에는 전혀 영향을 미치지 않지만 스레드가 충돌하면 프로세스의 다른 스레드가 모두 중단되고 스레드에 버퍼 오버런이 있으면 스레드가 열립니다. 모든 스레드의 보안 구멍.

따라서 통신 모듈을 거의 사용하지 않고 응용 프로그램 모듈을 대부분 독립적으로 실행할 수있는 경우 시작 및 종료 비용을 감당할 수있는 경우 프로세스를 사용해야합니다. IPC의 성능 저하는 최소화되며 버그 및 보안 허점에 대해 약간 더 안전합니다. 모든 약간의 성능이 필요한 경우 복잡한 데이터 구조와 같은 많은 공유 데이터를 얻거나 가질 수 있다면 스레드와 함께하십시오.


답변

다른 사람들은 고려 사항을 논의했습니다.

아마도 중요한 차이점은 Windows 프로세스에서는 스레드에 비해 무겁고 비싸고 Linux에서는 차이가 훨씬 작기 때문에 방정식의 균형이 다른 점입니다.


답변

옛날 옛적에 유닉스가 있었고이 오래된 유닉스에는 프로세스에 대한 오버 헤드가 많았 기 때문에 일부 영리한 사람들은 스레드를 만들었습니다.이 스레드는 부모 프로세스와 동일한 주소 공간을 공유하고 컨텍스트가 줄어 들었습니다. 컨텍스트 전환을보다 효율적으로 만드는 스위치입니다.

현대 리눅스 (2.6.x)에서는 스레드와 비교하여 프로세스의 컨텍스트 전환간에 성능에 큰 차이가 없습니다 (MMU 만 스레드에 추가됨). 공유 주소 공간에 문제가 있습니다. 이는 스레드의 잘못된 포인터가 상위 프로세스의 메모리 나 동일한 주소 공간 내의 다른 스레드를 손상시킬 수 있음을 의미합니다.

프로세스는 MMU에 의해 보호되므로 잘못된 포인터는 신호 11 만 발생하고 손상되지 않습니다.

일반적으로 프로세스 (Linux의 컨텍스트 스위치 오버 헤드는 아니지만 MMU로 인한 메모리 보호)를 사용하지만 실시간 스케줄러 클래스가 필요한 경우 pthread는 다른 차 한잔입니다.

Linux에서 스레드가 그렇게 큰 성능 향상을 가져 온다고 생각하는 이유는 무엇입니까? 이것에 대한 데이터가 있습니까, 아니면 단지 신화입니까?


답변

당신의 작업은 얼마나 밀접하게 결합되어 있습니까?

그들이 서로 독립적으로 살 수 있다면 과정을 사용하십시오. 서로 의존하는 경우 스레드를 사용하십시오. 이렇게하면 다른 작업의 작동을 방해하지 않고 나쁜 프로세스를 종료하고 다시 시작할 수 있습니다.


답변

설상가상으로, thread-local storage 및 Unix 공유 메모리와 같은 것이 있습니다.

스레드 로컬 저장소를 사용하면 각 스레드가 별도의 전역 개체 인스턴스를 가질 수 있습니다. 내가 사용한 유일한 시간은 RTOS에서 실행되는 응용 프로그램 코드를 위해 Linux / windows에서 에뮬레이션 환경을 만들 때였습니다. RTOS에서 각 작업은 자체 주소 공간이있는 프로세스 였고 에뮬레이션 환경에서 각 작업은 스레드 (공유 주소 공간이있는 스레드)였습니다. 싱글 톤과 같은 것에 TLS를 사용함으로써 우리는 ‘실제’RTOS 환경에서와 같이 각 스레드에 대해 별도의 인스턴스를 가질 수있었습니다.

공유 메모리는 여러 프로세스가 동일한 메모리에 액세스 할 때 성능 이점을 제공하지만 프로세스를 올바르게 동기화해야하는 비용 / 위험이 있습니다. 이를 수행하는 한 가지 방법은 하나의 프로세스가 공유 메모리에 데이터 구조를 작성한 다음 기존의 프로세스 간 통신 (명명 된 파이프)을 통해 해당 구조에 핸들을 보내는 것입니다.