어떤 스레드가 일반적으로 공유됩니까?


20

이것이 일반적인 질문입니다. 누구나 구현을 구체적으로 만들고 싶다면 유닉스 관련 것들을 선호합니다. 그러나 먼저 다음과 같은 일반적인 문제를 알아야합니다.

단일 프로세스에 여러 스레드가있을 수 있다고 읽었습니다. 동일한 프로세스의 여러 스레드가 서로 공유합니다. 나는 그들이 무엇을 공유하고 무엇을 알고 싶어요. 프로세스가 주소 공간, 스택, 힙, 전역 변수, 코드, 데이터, OS 리소스로 구성되어 있다고 생각하면 스레드에서 무엇을 공유합니까? 다음과 같은 추측이 있습니다.

  1. 전역 변수- 스레드 공유 전역 변수를 읽었습니다. 또한 Java 및 C #으로 프로그래밍하는 동안 클래스 수준 변수를 공유하기 위해 스레드를 만들었습니다. 따라서 스레드가 전역 변수를 공유한다고 생각합니다 (고수준 프로그래밍 언어의 개념이 운영 체제 수준의 사실과 같은지 여부는 확실하지 않습니다).

  2. 힙- 글로벌 변수는 힙에 저장되므로 힙은 스레드간에 공유됩니다.

  3. 스택- 각 스레드는 자체 실행 시퀀스 / 코드를 가질 수 있으므로 프로그램 카운터 내용을 푸시 / 팝핑 할 수있는 자체 스택이 있어야합니다 (함수 호출 및 리턴이 발생할 때). 따라서 동일한 프로세스의 스레드는 스택을 공유하지 않습니다.

이제 나는 다음 것들을 공유하는 것이 확실하지 않습니다.

  1. 주소 공간-주소 공간에서 정확히 무엇이 계산되는지 확실하지 않습니다. 그러나 주소 공간은 일반적으로 스레드가 아닌 프로세스 컨텍스트에서 사용됩니다. 동일한 프로세스의 모든 스레드가 상위 프로세스와 동일한 주소 공간에 상주하므로 스레드는 주소 공간을 공유한다고합니다. (그러나 그들은 동일한 주소 공간 내에서 다른 스택을 유지합니까?)

  2. OS 리소스- 구현에 따라 매우 다를 수 있습니다. 예를 들어, 부모 프로세스는 일부 파일을 처리하지 않고 일부 스레드에 동일한 파일을 처리 할 수 ​​있습니다. 또는 나는 착각하고 OS 자원은 파일 이외의 것을 의미합니까?

  3. 코드- 스레드는 다른 코드를 가질 수 있으므로 코드 공유가 항상 그런 것은 아닙니다.

  4. 데이터-데이터 에서 고려해야 할 사항이 확실하지 않습니다. 그러나 전역 변수는 스레드간에 공유되어야합니다. 지역 변수가 비슷하게 공유되지 않아야합니다.

전반적으로 나는 모호한 용어, 운영 체제 책에서 수행 된 수퍼 일반화 및 온라인으로 제공되는 추가 구현 관련 세부 사항으로 인해 상당히 혼란스러워합니다. 그래서 나는 나를 만족시킬 수있는 답변을 찾으려고 노력하고 있습니다.

답변:


13

일반적으로 각 스레드 에는 자체 레지스터 (자체 프로그램 카운터 포함), 자체 스택 포인터 및 자체 스택이 있습니다. 프로세스를 공유하는 스레드간에 다른 모든 것이 공유됩니다.

특히 프로세스 는 일반적으로 주소 공간, 힙, 정적 데이터 및 코드 세그먼트 및 파일 디스크립터 *를 공유하는 스레드 세트로 구성되는 것으로 간주됩니다 .

주소 공간은 단순히 물리적 메모리의 특정 조각 논리 주소의 매핑입니다. 따라서 프로세스의 모든 스레드가 동일한 주소 공간을 공유한다고 말하면 foo전역 범위 의 변수 에 액세스하면 모든 스레드가 동일한 변수를 보게됩니다. 마찬가지로 스레드는 특정 시간에 코드에서 다른 지점을 실행하고있을 수 있지만 bar()프로세스의 모든 스레드에 대해 동일한 함수에 해당하는 전역 함수를 호출 할 수 있습니다.

대부분의 최신 운영 체제는 공유되지 않는 전역 범위의 변수 인 스레드 로컬 스토리지 개념을 추가 했습니다. 이것을 사용하는 일반적인 예는 변수 errno입니다. 이는 전역 범위의 단일 변수이지만 대부분의 최신 운영 체제에서 각 스레드마다 자체 로컬 사본이 제공되므로 한 스레드의 라이브러리 호출 오류가 다른 스레드의 동작에 영향을 미치지 않습니다.

* 프로세스 ID, 신호 처리 및 파일 잠금과 같은 프로세스의 모든 스레드가 공유하는 일부 추가 프로세스 상태가 있습니다. 스레드가 공유하는 프로세스 상태의 전체 목록을 보려면 특정 스레딩 구현에 대한 설명서를 참조해야합니다. 예를 들어, pthreads 매뉴얼 페이지 입니다.


4

스레드는 운영 체제와 프로그래밍 언어의 두 가지 관점으로 나타납니다. 두 경우 모두 스레드의 속성에 약간의 차이가 있습니다.

스레드의 최소 정의는 순차적으로 발생하는 것입니다.

일반적인 머신 실행 모델에서 각 스레드에는 고유 한 범용 레지스터 세트와 고유 한 프로그램 카운터가 있습니다. 머신이 특정 레지스터를 스택 포인터로 설정하면 스레드 당 하나의 사본이 있습니다.

운영 체제 관점에서 스레드를 지원하기 위해 운영 체제가 수행해야하는 최소한의 스레드 간 전환 방법을 제공하는 것입니다. 이는 자동으로 ( 선점 형 멀티 태스킹 또는 스레드가 명시적인 요청을하는 경우에만 가능합니다 (협동 적 멀티 태스킹,이 경우 스레드는 파이버 라고도 함 ). 선점 및 협력 수율이 다른 하이브리드 모델도 있습니다 (예 : 다른 그룹의 스레드 간 선점) 또는 같은 그룹 / 태스크의 스레드간에 명시적인 수율로 작업을 수행하지만 스레드 간을 전환하려면 최소한 이전 스레드의 레지스터 값을 저장하고 새 스레드의 레지스터 값을 복원해야합니다.

작업 간 격리 를 제공하는 멀티 태스킹 운영 체제 (또는 프로세스 에서는 OS 컨텍스트에서이 용어를 동의어로 취급 할 수 있음)에서 각 작업에는 고유 한 리소스, 특정 주소 공간이 있지만 열린 파일, 권한 등이 있습니다. 위의 프로세스 인 엔티티 인 운영 체제 커널에 의해 제공됩니다 . 각 작업에는 일반적으로 하나 이상의 스레드가 있습니다. 코드를 실행하지 않는 작업은별로 사용되지 않습니다. 운영 체제는 동일한 작업에서 여러 스레드를 지원하거나 지원하지 않을 수 있습니다. 예를 들어 원래 유닉스는 그렇지 않았습니다. 작업은 여러 스레드를 전환하여 여러 스레드를 계속 실행할 수 있습니다. 특별한 권한이 필요하지 않습니다. 이것을 " 사용자 스레드 "라고 합니다”, 특히 유닉스 환경에서. 오늘날 대부분의 유닉스 시스템은 커널 스레드를 제공합니다. 특히 다른 프로세서에서 동일한 프로세스의 여러 스레드를 실행하는 유일한 방법이기 때문입니다.

계산 시간을 제외한 대부분의 운영 체제 리소스는 스레드가 아닌 작업에 연결됩니다. 일부 운영 체제 (예 : Linux)는 스택을 명시 적으로 구분하며,이 경우 각 스레드마다 고유 한 스택이 있습니다. 그러나 커널이 스택에 대해 아무것도 모르는 OS가 있으며, 우려되는 한 힙의 일부입니다. 커널은 또한 일반적으로 각 스레드에 대한 커널 컨텍스트를 관리합니다. 이는 스레드가 현재 수행중인 작업에 대한 정보를 포함하는 데이터 구조입니다. 이를 통해 커널은 시스템 호출에서 차단 된 여러 스레드를 동시에 처리 할 수 ​​있습니다.

운영 체제와 관련하여 작업의 스레드는 동일한 코드를 실행하지만 해당 코드에서 다른 위치에 있습니다 (다른 프로그램 카운터 값). 프로그램 코드의 특정 부분은 항상 특정 스레드에서 실행되지만 발생하지 않을 수도 있지만 일반적으로 모든 스레드에서 호출 할 수있는 공통 코드 (예 : 유틸리티 함수)가 있습니다. 모든 스레드는 동일한 데이터를보고 그렇지 않으면 다른 작업으로 간주됩니다. 일부 데이터가 특정 스레드에서만 액세스 할 수있는 경우 일반적으로 운영 체제가 아닌 프로그래밍 언어의 범위입니다.

대부분의 프로그래밍 언어에서 스토리지는 동일한 프로그램의 스레드간에 공유됩니다. 동시 프로그래밍 의 공유 메모리 모델입니다. 경쟁 조건 이 발생할 수 있으므로 여러 스레드에서 동일한 데이터에 액세스 할 수있을 때 프로그래머가주의해야하기 때문에 매우 인기가 있지만 오류가 발생하기 쉽습니다 . 로컬 변수도 스레드간에 공유 할 수 있습니다. "로컬 변수"(보통)는 함수를 한 번만 실행할 때만 이름이 유효한 변수를 의미하지만 다른 스레드는 해당 변수에 대한 포인터를 얻어 액세스 할 수 있습니다.

각 스레드마다 자체 스토리지가있는 프로그래밍 언어가 있으며 이들 사이의 통신은 통신 채널을 통해 메시지를 전송하여 발생합니다. 동시 프로그래밍 의 메시지 전달 모델입니다. 에를 랑메시지 전달에 중점을 둔 주요 프로그래밍 언어입니다. 실행 환경은 스레드를 매우 가볍게 처리하며 스레드 생성이 상대적으로 비용이 많이 들고 런타임 환경이 크게 지원할 수없는 대부분의 다른 프로그래밍 언어와 달리 많은 단기 스레드로 작성된 프로그램을 권장합니다. 동시에 스레드 수. Erlang의 순차 서브 세트 (스레드 내에서 발생하는 언어의 일부, 특히 데이터 조작)는 (주로) 순전히 기능적입니다. 따라서 스레드는 일부 데이터를 포함하는 다른 스레드로 메시지를 보낼 수 있으며 스레드가 사용하는 동안 다른 스레드가 데이터를 수정하는 것에 대해 걱정할 필요가 없습니다.

일부 언어는 유형 시스템을 사용하거나 사용하지 않고 스레드 로컬 스토리지를 제공하여 스레드 로컬 스토리지 위치를 글로벌 로컬 스토리지와 구별하여 두 모델을 혼합합니다. 스레드 로컬 저장소는 일반적으로 변수 이름으로 다른 스레드에서 다른 저장소 위치를 지정할 수있는 편리한 기능입니다.

어떤 스레드가 무엇인지 이해하는 데 관심이있을 수있는 일부 (어려운) 후속 조치 :

  • 여러 스레드를 지원하기 위해 커널이 수행해야하는 최소값은 얼마입니까?
  • 멀티 프로세서 환경에서 한 프로세서에서 다른 프로세서로 스레드를 마이그레이션하려면 무엇이 필요합니까?
  • 운영 체제의 지원없이 내장 된 지원을 사용하지 않고 선호하는 프로그래밍 언어로 협동 멀티 스레딩 ( 코 루틴 ) 을 구현 하려면 무엇이 필요할까요? (대부분의 프로그래밍 언어에는 단일 스레드 내에서 코 루틴을 구현하는 데 필요한 기본 요소가 없습니다.)
  • 프로그래밍 언어에 동시성이 있지만 스레드 개념이없는 경우 어떻게 보일 수 있습니까? (프라임 예 : pi-calculus .)

이것은 몇 달 동안 읽은 가장 흥미로운 것입니다.
JSON

2

조건에 따라서. POSIX (및 Unix 시스템에서 제공) 또는 Windows (나중에 익숙하지 않은 경우)에 의해 정의 된 스레드를 고려하면 대답을 제공합니다 (본질적으로 @WanderingLogic 답변 설명). Linux는 비표준 clone(2)시스템 호출을 사용하여 고유 한 스레드 개념을 가지고 있습니다. 부모와 자식이 공유하는 내용을보다 세밀하게 제어 할 수 있습니다. 내부 플래그 를 포함 fork(2)하고 vfork(2)본질적으로 래퍼를 clone(2)가지고 특정 플래그로 호출합니다. 즉, 부모와 아무것도 공유하지 않는 "스레드"를 만들 수 있습니다. 자세한 내용은 매뉴얼 페이지를 참조 하십시오 . 예를 들어 여기에서 온라인으로 제공 됩니다 . 예, Linux는 POSIX 스타일 스레드를 제공하지만 그 외에는 더 많은 기능이 있습니다.


0

스레드 공유 :

  • 주소 공간
  • 더미
  • 정적 데이터
  • 코드 세그먼트
  • 파일 기술자
  • 글로벌 변수
  • 자식 프로세스
  • 대기중인 알람
  • 신호 및 신호 처리기
  • 회계 정보

스레드는 자신의 것을 가지고 있습니다 :

  • 프로그램 카운터
  • 레지스터
  • 스택
  • 상태
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.