2012-09-12 5 views
4

forkIO를 사용하여 스레드를 만들면 실행하고 식별자 (threadID)를 돌려받는 함수를 제공해야합니다. 그런 다음이 동물과 의사 소통 할 수 있습니다. 워크로드, MVAR 등. 그러나, 내 이해하기 위해 만들어진 스레드는 매우 제한되어 있으며 일종의 SIMD 패션에서만 작동 할 수 있습니다. 스레드 생성을 위해 제공된 함수가 명령어입니다. 스레드가 시작될 때 제공 한 기능을 변경할 수 없습니다. 나는이 사용자 스레드가 결국 OS 스레드로 매핑 된 OS에 의한다는 것을 이해합니다.forkIO 스레드와 OS 스레드

하스켈 스레드와 OS 스레드가 인터페이스를 수행하는 방법을 알고 싶습니다. 왜 완전히 다른 것들을하는 Haskell 쓰레드가 하나의 동일한 OS 쓰레드에 매핑 될 수 있습니까? 왜 고정 명령으로 OS 스레드를 시작할 필요가 없었습니까 (forkIO에서 필요함)? 스케줄러 (?)는 배포 될 수있는 응용 프로그램의 사용자 스레드를 어떻게 인식합니까? 즉, OS 스레드가 왜 유연한가요?

마지막으로 응용 프로그램 내에서 선택한 스레드의 힙을 덤프 할 수있는 방법이 있습니까?

+2

http://community.haskell.org/~simonmar/papers/conc-ffi.pdf를 읽는 것이 좋을지도 모릅니다.이 문서는 멀티 스레딩 된 Haskell의 구현을 설명하는 훌륭한 작업입니다. 조금 오래되었지만 여전히 관련성이 높습니다. 제목에도 불구하고, 그것은 FFI보다 훨씬 더 중요합니다. –

답변

10

먼저, 하나의 빠른 오해를 해결하자

내가 이러한 사용자 스레드가 OS 스레드에 매핑 된 OS에 의해 결국 것으로 알고 있습니다.

사실, Haskell 런타임은 풀에서 특정 OS 스레드가 실행중인 Haskell 스레드를 선택합니다.

이제 질문을 한 번에 하나씩.

왜 완전히 다른 작업을하는 하스켈 스레드가 하나의 동일한 OS 스레드에 매핑 될 수 있습니까?

모든 OS 스레드는 실제로 Haskell 런타임을 실행 중입니다.이 스레드는 준비된 하스켈 스레드 목록을 추적합니다. 런타임은 실행할 Haskell 스레드를 선택하고 스레드가 런타임에 제어권을 반환 할 때까지 실행하여 코드로 점프합니다. 이때 런타임은 동일한 스레드를 계속 실행하거나 다른 스레드를 선택할 기회가 있습니다.

간단히 말해 : 많은 하스켈 스레드가 하나의 OS 스레드로 매핑 될 수 있습니다. 실제로 OS 스레드가 하스켈 런타임을 실행하는 것 하나만하기 때문입니다.

고정 명령으로 OS 스레드를 시작할 필요가없는 이유는 무엇입니까 (forkIO에서 필요함)?

나는이 질문을 이해하지 못한다. (나는 두 번째 오해에서 유래한다고 생각한다.) 고정 된 명령어로 고정 된 명령어로 하스켈 스레드를 시작하는 것과 똑같이 고정 된 명령어로 OS 스레드를 시작합니다. 각 일에 대해 실행할 코드 덩어리를 제공하기 만하면됩니다.

스케줄러 (?)는 배포 할 수있는 응용 프로그램의 사용자 스레드를 어떻게 인식합니까?

"분산 형"은 위험한 단어입니다. 일반적으로 여러 컴퓨터에 코드를 분산시키는 것을 말합니다 (여기에서 의도 한 것과 다를 수 있음). 하스켈 런타임이 다중 쓰레드가 언제인지를 알 수있는 방법은 간단합니다. forkIO에 전화하면 알려줍니다.

즉, 왜 OS 스레드가 유연합니까?

OS 스레드가 하스켈 스레드보다 더 유연하다는 것은 확실하지 않으므로이 질문은 약간 이상합니다.

마지막으로 응용 프로그램 내에서 선택한 스레드의 힙을 덤프 할 수있는 방법이 있습니까?

실제로 멀티 스레드 응용 프로그램이나 다른 방법으로 하스켈 힙을 전혀 덤프 할 수있는 도구는 실제로 모르겠습니다. vacuum과 같은 패키지를 사용하여 원하는 경우 특정 객체에서 도달 할 수있는 힙 부분의 표현을 덤프 할 수 있습니다. 나는이 덤프를 시각적으로 나타 내기 위해 vacuum-cairo을 사용해 봤습니다.

더 많은 정보를 얻으려면 ""에서 "관례"및 "해외 가져 오기"중간 두 섹션과 "비 스레드 런타임"섹션의 비트를 즐길 수 있습니다.

+0

''forkOS'는 non-haskell 코드와 더 쉽게 인터페이스 할 수 있다는 점에서보다 유연합니다. –

+1

@PhilipJF 글쎄, 모든 멀티 스레딩 클레임에주의를 기울여야하며, 예외는 아닙니다. 스레드로 로컬 상태 (OS-)를 사용하는 API로 여러 번 호출하는 스레드 만'forkIO'에서'forkOS'로 전환해야합니다. 다른 모든 것들은 완전히 훌륭한 대안으로'forkIO'를 가지고 있습니다. –

+0

예. 나는 아마 "조금 더 쉽게"라고 말했어 야했다. –

8

질문에 직접 답하는 대신 멀티 스레딩 하스켈 프로그램을 구현하는 방법에 대한 개념적 모델을 제공하려고합니다. 나는 많은 세부 사항과 복잡성을 무시할 것이다.

운영 체제는 preemptive multithreading을 사용하여 hardware interrupts을 사용하여 여러 개의 "스레드"계산이 동일한 코어에서 동시에 논리적으로 실행될 수 있도록합니다.

운영 체제에서 제공하는 스레드는 중량이 큰 경향이 있습니다. 이들은 특정 유형의 "멀티 스레드"응용 프로그램에 매우 적합하며 Linux와 같은 시스템에서는 기본적으로 여러 프로그램을 동시에 실행할 수있는 동일한 도구 (탁월한 작업)를 제공합니다.

그러나이 스레드는 하스켈 (Haskell)과 같은 고급 언어에서 많은 용도로 사용하기에는 비트 중량이 큽니다. 본질적으로 GHC 런타임은 OS가 코어 위에 스레드를 구현하는 것과 같은 방식으로 OS 스레드 위에 자체 "스레드"를 구현하는 미니 OS로 작동합니다.

하스켈 (Haskell)과 같은 언어가 이러한 방식으로 구현된다고 상상하기 란 개념 상 쉽습니다. Haskell 평가는 "썽크 강제"로 구성됩니다. 썽크는 다른 값 (썽크)에 의존하거나 새로운 썽크를 만들 수있는 계산 단위입니다.

따라서 각각 동시에 썽크를 평가하는 여러 스레드를 상상할 수 있습니다. 하나는 평가받을 썽크 대기열을 만듭니다. 각 스레드는 대기열의 맨을 팝하고 완료 될 때까지 해당 썽크를 평가 한 다음 대기열에서 새 썽 크를 선택합니다. 작업 par과 그 ilk는 해당 큐에 썽크를 추가하여 새로운 계산을 "촉발"시킬 수 있습니다.

이 모델을 IO 작업으로 확장하는 것은 상상하기가 특히 어렵지 않습니다. 각각 단순하게 순수한 썽크를 강요하는 대신, 우리는 하스켈 계산의 단위가 다소 복잡하다고 상상합니다.

type Spark = (ThreadId,Action) 
data Action = Compute Thunk | Perform IOAction 

참고 : 같은 런타임 사이비 하스켈이 일이 이런 식으로

우리가 불꽃을 실행하면, 우리는 예외를 찾아 "던져"에 구현되어 생각하지 않는다, 단지 개념 이해를위한 것입니다 그 스레드 ID. 아무 것도 없다고 가정하면 실행은 썽크를 강요하거나 IO 작업을 수행하는 것으로 구성됩니다.

분명히 여기서 나의 설명은 매우 손이 물결 치고 약간의 복잡성을 무시했다. 더 많은 것을 위해 GHC 팀은 Marlow et al.의 "Runic Support for Multicore Haskell"과 같은 우수한 기사를 작성했습니다. 운영 체제의 텍스트 북을보고 싶을 수도 있습니다. 종종 스케줄러를 작성하는 방법에 대해 깊이있는 내용을 다루기 때문입니다.

관련 문제