Low-Level-Details der Implementierung von performSelectorOnMainThread:

8

Ich frage mich, ob jemand weiß, oder hat Zeiger auf gute Dokumentation, die bespricht, die Low-Level-Implementierung Details von Cocoa 'performSelectorOnMainThread: -Methode.

Meine beste Vermutung, und ich denke, es ist wahrscheinlich ziemlich nahe, ist, dass es Mach-Ports oder eine Abstraktion auf ihnen verwendet, um In-Thread-Kommunikation bereitzustellen und Selektorinformationen als Teil der Mach-Nachricht weiterzuleiten.

>

Richtig? Falsch? Danke!

Update 09:39 AMPST

Danke Evan DiBiase und Mecki für die Antworten, aber um zu verdeutlichen: Ich verstehe was in der Laufschleife passiert, aber worauf ich eine Antwort suche ist; " wo ist die Methode in die Warteschlange gestellt? Wie werden die Selektorinformationen in die Warteschlange übertragen?" Auf der Suche nach mehr als Apples Doc-Info: Ich habe sie gelesen

Update 14: 21PST

Chris Hanson bringt einen guten Punkt in einem Kommentar: Mein Ziel hier ist nicht, die zugrunde liegenden Mechanismen zu lernen, um sie in meinem eigenen Code auszunutzen. Ich bin nur an einem besseren konzeptionellen Verständnis des Prozesses der Signalisierung eines anderen Threads interessiert, um Code auszuführen. Wie gesagt, meine eigenen Recherchen führen mich zu der Annahme, dass Mach-Messaging für IPC nutzt, um Selektorinformationen zwischen Threads weiterzuleiten, aber ich suche gezielt nach konkreten Informationen darüber, was gerade passiert kann sicher sein, dass ich die Dinge richtig verstehe . Vielen Dank!

Update 03/06/09

Ich habe ein Kopfgeld für diese Frage eröffnet, weil ich es gerne beantwortet sehen würde, aber wenn du versuchst zu sammeln, vergewissere dich bitte, dass du alles gelesen hast, einschließlich aller aktuell gestellten Antworten, Kommentare zu diesen Antworten und zu meiner ursprünglichen Frage sowie den Update-Text, den ich oben gepostet habe. Ich suche nach dem Detail der niedrigsten Ebene des von performSelectorOnMainThread: und ähnlichem verwendeten Mechanismus, und wie ich bereits erwähnt habe, vermute ich, dass es etwas mit Mach-Ports zu tun hat, aber ich würde es wirklich tun möchte es sicher wissen. Das Kopfgeld wird nur vergeben, wenn ich bestätigen kann, dass die Antwort richtig ist. Danke an alle!

    
rpj 29.09.2008, 16:06
quelle

4 Antworten

10

Ja, es verwendet Mach-Ports. Was passiert ist das:

  1. Ein Datenblock, der die Ausführungsinformationen kapselt (das Zielobjekt, der Selektor, das optionale Objektargument für den Selektor usw.), wird in die Run-Loop-Information des Threads eingereiht. Dies geschieht mithilfe von @synchronized , die letztendlich pthread_mutex_lock verwendet.
  2. CFRunLoopSourceSignal wird aufgerufen, um zu signalisieren, dass die Quelle schussbereit ist.
  3. CFRunLoopWakeUp wird aufgerufen, damit die Ausführungsschleife des Hauptthreads weiß, dass es Zeit ist, aufzuwachen. Dies geschieht mit mach_msg.

Aus den Apple-Dokumenten:

  

Quellen der Version 1 werden von der Ausführungsschleife und dem Kernel verwaltet. Diese Quellen verwenden Mach-Ports, um zu signalisieren, wann die Quellen schussbereit sind. Eine Quelle wird automatisch vom Kernel signalisiert, wenn eine Nachricht am Mach-Port der Quelle ankommt. Der Inhalt der Nachricht wird an die Quelle gesendet, die verarbeitet werden soll, wenn die Quelle ausgelöst wird. Die Runloop-Quellen für CFMachPort und CFMessagePort werden derzeit als Quellen der Version 1 implementiert.

Ich schaue mir gerade eine Stack-Spur an, und das ist es, was es zeigt:

%Vor%

Setzen Sie einen Haltepunkt auf mach_msg und Sie können ihn bestätigen.

    
Tony 06.03.2009, 20:30
quelle
2

Eine weitere Bearbeitung:

Um die Frage des Kommentars zu beantworten:

  

Welcher IPC-Mechanismus wird verwendet?   Informationen zwischen Threads weitergeben? Geteilt   Erinnerung? Steckdosen? Mach Messaging?

NSThread speichert intern einen Verweis auf den Haupt-Thread und über diesen Verweis können Sie einen Verweis auf den NSRunloop dieses Threads erhalten. Ein NSRunloop ist intern eine verknüpfte Liste und durch Hinzufügen eines NSTimer-Objekts zum Runloop wird ein neues verknüpftes Listenelement erstellt und zur Liste hinzugefügt. Man könnte also sagen, es ist Shared Memory, die verknüpfte Liste, die eigentlich zum Hauptthread gehört, wird einfach in einem anderen Thread geändert. Es gibt Mutexe / Locks (möglicherweise sogar NSLock-Objekte), die sicherstellen, dass die Bearbeitung der verknüpften Liste Thread-sicher ist.

Pseudocode:

%Vor%

Natürlich ist das zu stark vereinfacht, die meisten Details sind hier zwischen Funktionen versteckt. Z.B. getNextTask gibt nur dann einen Timer zurück, wenn der Timer bereits ausgelöst wurde. Wenn das Feuerdatum für jeden Timer noch in der Zukunft liegt und kein anderes Ereignis zu verarbeiten ist (wie eine Tastatur, ein Mausereignis von der Benutzeroberfläche oder eine gesendete Benachrichtigung), würde NULL zurückgegeben.

Ich bin mir immer noch nicht sicher, was die Frage ist. Ein Selektor ist nichts anderes als eine C-Zeichenfolge, die den Namen einer aufgerufenen Methode enthält. Jede Methode ist eine normale C-Funktion und es existiert eine String-Tabelle, die die Methodennamen als Strings und Funktionszeiger enthält. Das sind die Grundlagen, wie Objective-C tatsächlich funktioniert.

Wie ich unten geschrieben habe, wird ein NSTimer-Objekt erstellt, das einen Zeiger auf das Zielobjekt und einen Zeiger auf eine C-Zeichenfolge mit dem Methodennamen erhält. Wenn der Timer ausgelöst wird, findet es die richtige C-Methode, die mit der Zeichenfolge aufgerufen wird Tabelle (daher benötigt es den String-Namen der Methode) des Zielobjekts (daher benötigt es einen Verweis darauf).

Nicht genau die Implementierung, aber ziemlich nah dran:

Jeder Thread in Cocoa hat einen NSRunLoop (es ist immer da, du musst nie für einen Thread erstellen). PerformSelectorOnMainThread erstellt ein NSTimer-Objekt wie dies , eine, die nur einmal feuert und die Zeit zum Feuern bereits in der Vergangenheit liegt (also sofort feuern muss), dann erhält sie den NSRunLoop von Haupt-Thread und fügt das Timer-Objekt dort hinzu. Sobald der Hauptthread inaktiv ist, sucht er nach dem nächsten Ereignis in seinem Runloop, das verarbeitet werden soll (oder geht in den Ruhezustand, wenn nach dem Hinzufügen eines Ereignisses nichts mehr zu verarbeiten und wieder aufzuwachen ist) ) und führt es aus. Entweder ist der Haupt-Thread beschäftigt, wenn Sie den Anruf planen, in diesem Fall verarbeitet er das Timer-Ereignis, sobald es seine aktuelle Aufgabe beendet hat oder es gerade schläft. In diesem Fall wird es durch Hinzufügen des Ereignisses geweckt und verarbeitet es sofort.

Eine gute Quelle, um nachzusehen, wie Apple es am wahrscheinlichsten macht (niemand kann das mit Sicherheit sagen, wie auch immer seine geschlossene Quelle) ist GNUStep. Da der GCC mit Objective-C umgehen kann (es ist nicht nur eine Erweiterung, sondern sogar Standard-GCC), aber Obj-C ohne all die grundlegenden Klassen, die Apple-Schiffe verwenden, ist ziemlich nutzlos -Umsetzen Sie die am häufigsten verwendeten Obj-C-Klassen, die Sie auf Mac verwenden, und deren Implementierung ist OpenSource.

Hier können Sie ein aktuelles Quellpaket herunterladen.

Entpacken Sie das Paket und werfen Sie einen Blick auf die Implementierung von NSThread, NSObject und NSTimer für Details. Ich nehme an, dass Apple es nicht viel anders macht, ich könnte es wahrscheinlich mit gdb beweisen, aber warum sollten sie es anders machen als diese Herangehensweise? Es ist ein cleverer Ansatz, der sehr gut funktioniert:)

    
Mecki 29.09.2008 16:27
quelle
2

Das Dokumentation für die Methode performSelectorOnMainThread:withObject:waitUntilDone: von NSObject lautet:

  

Diese Methode reiht die Nachricht in der Ausführungsschleife des Haupt-Threads unter Verwendung der Standardlaufmodus-Modi ein, dh der Modi, die mit dem NSRunLoopCommonModes Konstante. Als Teil seiner normalen Laufschleifenverarbeitung entfernt der Haupt-Thread die Nachricht aus der Warteschlange (unter der Annahme, dass sie in einem der Standardlaufmodus-Modi läuft) und ruft die gewünschte Methode auf.

    
Evan DiBiase 29.09.2008 16:21
quelle
0

Wie Mecki sagte, ist ein allgemeinerer Mechanismus zur Implementierung von -performSelectorOn… NSTimer .

NSTimer ist gebührenfrei überbrückt zu CFRunLoopTimer . Eine Implementierung von CFRunLoopTimer - obwohl nicht notwendigerweise diejenige, die tatsächlich für normale Prozesse in OS X verwendet wird - kann in CFLite gefunden werden (Open-Source-Teilmenge von CoreFoundation; Paket CF-476.14 in der Darwin 9.4-Quellcode . (CF-476.15, entsprechend OS X 10.5.5, ist noch nicht verfügbar.)

    
Jens Ayton 29.09.2008 23:20
quelle

Tags und Links