문제

Cocoa의 'performSelectorOnMainThread:' 메소드의 저수준 구현 세부 사항을 논의하는 좋은 문서에 대한 포인터를 알고 있거나 아는 사람이 있는지 궁금합니다.

내 생각에 가장 가깝고 아마도 꽤 유사하다고 생각되는 것은 mach 포트 또는 그 위에 추상화를 사용하여 스레드 내 통신을 제공하고 mach 메시지의 일부로 선택기 정보를 전달한다는 것입니다.

오른쪽?잘못된?감사해요!

업데이트 오전 9시 39분

답변을 주신 Evan DiBiase와 Mecki에게 감사드립니다. 하지만 명확히 하자면:나는 런 루프에서 어떤 일이 일어나는지 이해합니다. 그러나 내가 찾고 있는 대답은 다음과 같습니다."어디 메소드가 대기 중입니까? 어떻게 선택기 정보가 대기열로 전달되고 있습니까?" Apple의 문서 정보 이상의 정보를 찾고 있습니다.나는 그것을 읽었다

업데이트 14:21PST

Chris Hanson은 의견에서 좋은 점을 제시합니다.여기서 나의 목표는 내 코드에서 이를 활용하기 위해 기본 메커니즘을 배우는 것이 아닙니다.오히려 나는 코드를 실행하기 위해 다른 스레드에 신호를 보내는 프로세스에 대한 더 나은 개념적 이해에 관심이 있습니다.내가 말했듯이, 내 자신의 연구에 따르면 IPC가 스레드 간에 선택기 정보를 전달하는 데 mach 메시징을 활용한다고 믿게 되었지만 특별히 찾고 있는 것은 다음과 같습니다. 콘크리트 무슨 일이 일어나고 있는지에 대한 정보를 제공하므로 상황을 확실히 이해하고 있음을 확인할 수 있습니다. 바르게.감사해요!

업데이트 03/06/09

이 질문에 대한 답변을 꼭 보고 싶어서 현상금을 걸었습니다. 하지만 수집하려는 경우 꼭 읽어보시기 바랍니다. 모든 것, 현재 제기된 모든 답변, 이 답변과 원래 질문에 대한 의견, 위에 게시한 업데이트 텍스트를 포함합니다.나는 ~을 찾고 있다 가장 낮은 수준의 세부정보 사용되는 메커니즘의 performSelectorOnMainThread: 그리고 앞서 언급했듯이 Mach 포트와 관련이 있는 것으로 의심되지만 확실히 알고 싶습니다.내가 할 수 없으면 현상금이 수여되지 않습니다. 확인하다 주어진 대답은 정확합니다.모두 감사합니다!

도움이 되었습니까?

해결책

예, 마하 포트를 사용합니다. 이런 일은 다음과 같습니다.

  1. 실적 정보 (대상 객체, 선택기, 선택적 객체 인수 등)를 캡슐화하는 데이터 블록은 스레드의 실행 루프 정보에 큐를 제공합니다. 이것은 사용합니다 @synchronized, 궁극적으로 사용하는 pthread_mutex_lock.
  2. cfrunloopsourcesignal은 소스가 발사 될 준비가되었음을 알리기 위해 호출됩니다.
  3. Cfrunloopwakeup은 메인 스레드의 런 루프에 깨어날 시간임을 알리도록 요청되었습니다. 이것은 mach_msg를 사용하여 수행됩니다.

사과 문서에서 :

버전 1 소스는 런 루프 및 커널에 의해 관리됩니다. 이 소스는 마하 포트를 사용하여 소스가 발사 될 준비가되었을 때 신호를 보냅니다. 소스가 소스의 마하 포트에 도착하면 커널에 의해 소스가 자동으로 신호를받습니다. 메시지의 내용은 소스가 발사 될 때 프로세스를 위해 소스에 제공됩니다. CFMachport 및 CFMessagePort 용 Run Loop 소스는 현재 버전 1 소스로 구현됩니다.

나는 지금 스택 추적을보고있다. 그리고 이것이 보여준 것입니다.

0 mach_msg
1 CFRunLoopWakeUp
2 -[NSThread _nq:]
3 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:]
4 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:]

mach_msg에서 중단 점을 설정하면 확인할 수 있습니다.

다른 팁

한 번 더 편집:

의견의 질문에 답하려면 다음을 수행하십시오.

스레드간에 정보를 전달하는 데 어떤 IPC 메커니즘이 사용되고 있습니까?공유 메모리?소켓?마하 메시징?

NSThread는 내부적으로 메인 스레드에 대한 참조를 저장하고 해당 참조를 통해 해당 스레드의 NSRunloop에 대한 참조를 얻을 수 있습니다.NSRunloop는 내부적으로 연결된 목록이며 NSTimer 개체를 runloop에 추가하면 새로운 연결된 목록 요소가 생성되어 목록에 추가됩니다.따라서 실제로 메인 스레드에 속하는 연결된 목록이 다른 스레드 내에서 수정되는 공유 메모리라고 말할 수 있습니다.연결된 목록 편집이 스레드로부터 안전한지 확인하는 뮤텍스/잠금(NSLock 개체도 가능)이 있습니다.

의사 코드:

// Main Thread

for (;;) {
    lock(runloop->runloopLock);
    task = NULL;
    do {
        task = getNextTask(runloop);
        if (!task) {
            // function below unlocks the lock and
            // atomically sends thread to sleep.
            // If thread is woken up again, it will
            // get the lock again before continuing
            // running. See "man pthread_cond_wait"
            // as an example function that works
            // this way
            wait_for_notification(runloop->newTasks, runloop->runloopLock);
        }
    } while (!task);
    unlock(runloop->runloopLock);
    processTask(task);
}


// Other thread, perform selector on main thread
// selector is char *, containing the selector
// object is void *, reference to object

timer = createTimerInPast(selector, object);
runloop = getRunloopOfMainThread();
lock(runloop->runloopLock);
addTask(runloop, timer);
wake_all_sleeping(runloop->newTasks);
unlock(runloop->runloopLock);

물론 이것은 지나치게 단순화되었으며 대부분의 세부 사항은 여기의 기능 사이에 숨겨져 있습니다.예:getNextTask는 타이머가 이미 실행되어야 하는 경우에만 타이머를 반환합니다.모든 타이머의 실행 날짜가 여전히 미래이고 처리할 다른 이벤트(예: 키보드, UI의 마우스 이벤트 또는 전송된 알림)가 없는 경우 NULL을 반환합니다.


나는 아직도 질문이 무엇인지 잘 모르겠습니다.ㅏ 선택자 호출되는 메소드의 이름을 포함하는 C 문자열에 지나지 않습니다.모든 메소드는 일반 C 함수이며 메소드 이름을 문자열 및 함수 포인터로 포함하는 문자열 테이블이 있습니다.이것이 Objective-C가 실제로 작동하는 가장 기본적인 방법입니다.

아래에 쓴 것처럼 대상 객체에 대한 포인터와 메서드 이름이 포함된 C 문자열에 대한 포인터를 가져오는 NSTimer 객체가 생성되고 타이머가 실행되면 문자열 테이블을 사용하여 호출할 올바른 C 메서드를 찾습니다. 대상 개체의 메서드 문자열 이름이 필요합니다(따라서 이에 대한 참조가 필요함).

정확히 구현된 것은 아니지만 거의 비슷합니다.

Cocoa의 모든 스레드에는 NSRunLoop이 있습니다(항상 존재하므로 스레드에 대해 생성할 필요가 없습니다).PerformSelectorOnMainThread는 다음과 같은 NSTimer 객체를 생성합니다. 이것, 한 번만 실행되고 실행 시간이 이미 과거에 있는 경우(즉시 실행해야 함), 메인 스레드의 NSRunLoop를 가져오고 거기에 타이머 개체를 추가합니다.메인 스레드가 진행되자마자 게으른, 자신의 Runloop에서 처리할 다음 이벤트를 찾아서(또는 처리할 것이 없으면 Sleep 상태가 되고 이벤트가 추가되자마자 다시 깨어남) 수행합니다.호출을 예약할 때 메인 스레드가 사용 중입니다. 이 경우 현재 작업이 완료되자마자 타이머 이벤트를 처리하거나 현재 잠자고 있는 경우 이벤트를 추가하여 깨어납니다. 그리고 즉시 처리합니다.

Apple이 어떤지 알아볼 수 있는 좋은 자료 아마 그렇게 할 거야 (모든 비공개 소스가 있기 때문에 아무도 확실히 말할 수 없습니다)는 GNUStep입니다.GCC는 Objective-C를 처리할 수 있기 때문에(Apple만이 제공하는 확장이 아니라 표준 GCC도 이를 처리할 수 있음) Apple이 제공하는 모든 기본 클래스 없이 Obj-C를 갖는 것은 다소 쓸모가 없기 때문에 GNU 커뮤니티는 다시 시도했습니다. -Mac에서 사용하는 가장 일반적인 Obj-C 클래스를 구현하고 그 구현은 OpenSource입니다.

여기 최신 소스 패키지를 다운로드할 수 있습니다.

압축을 풀고 NSThread, NSObject 및 NSTimer의 구현을 자세히 살펴보세요.제 생각에는 Apple이 크게 다르지 않은 것 같습니다. 아마도 gdb를 사용하여 증명할 수 있을 것입니다. 하지만 왜 Apple은 그 접근 방식과 크게 다른가요?매우 잘 작동하는 영리한 접근 방식입니다 :)

그만큼 nsObject의 문서 performSelectorOnMainThread:withObject:waitUntilDone: 방법 말 :

이 메소드는 기본 실행 루프 모드, 즉 관련 모드를 사용하여 기본 스레드의 실행 루프에서 메시지를 대기합니다. nsrunloopcommonmodes 끊임없는. 정상적인 실행 루프 처리의 일환으로, 기본 스레드는 메시지를 비우기 (기본 실행 루프 모드 중 하나에서 실행중인 것으로 가정하고) 원하는 메소드를 호출합니다.

Mecki가 말했듯이, 구현에 사용될 수있는보다 일반적인 메커니즘 -performSelectorOn… ~이다 NSTimer.

NSTimer 통행료가없는 다리 CFRunLoopTimer. 의 구현 CFRunLoopTimer -OS X의 정상 프로세스에 실제로 사용되는 것은 아니지만 CFLITE (CoreFoundation의 오픈 소스 서브 세트; 패키지 CF-476.14에서 찾을 수는 없습니다. 다윈 9.4 소스 코드. (OS X 10.5.5에 해당하는 CF-476.15는 아직 사용할 수 없습니다.)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top