dispatch_queue_set_specific vs. immer die aktuelle Warteschlange
Ich versuche, meinen Kopf um die Differenz und der Nutzung zwischen diese 2:
static void *myFirstQueue = "firstThread";
dispatch_queue_t firstQueue = dispatch_queue_create("com.year.new.happy", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_set_specific(firstQueue, myFirstQueue, (void*) myFirstQueue, NULL);
Frage #1
Was ist der Unterschied zwischen diesem:
dispatch_sync(firstQueue, ^{
if(dispatch_get_specific(myFirstQueue))
{
//do something here
}
});
sowie die folgenden:
dispatch_sync(firstQueue, ^{
if(firstQueue == dispatch_get_current_queue())
{
//do something here
}
});
?
Frage #2:
Anstatt mithilfe der oben genannten (void*) myFirstQueue
im
dispatch_queue_set_specific(firstQueue, myFirstQueue, (void*) myFirstQueue, NULL);
Können wir static int * myFirstQueue = 0;
statt ?
Meine Argumentation basiert auf der Tatsache, dass:
dispatch_once_t
ist auch 0 (gibt es eine Korrelation hier? Übrigens, ich weiß noch nicht so Recht, warum dispatch_once_t
muss initialisiert werden auf 0, obwohl ich bereits gelesen haben, Fragen hier SO).
Frage #3
Können, die Sie zitieren mich ein Beispiel von GCD Deadlock hier?
Frage #4
Diese vielleicht ein wenig zu viel verlangt; ich werde Sie trotzdem bitten, im Fall jemand wissen, geschieht dies außerhalb der auf der Oberseite des Kopfes. Wenn nicht, wäre es OK zu verlassen, ist dieser Teil offen.
Habe ich noch nicht ausprobiert, weil ich wirklich nicht weiß, wie. Aber mein Konzept ist dieses:
Ist es auf jeden Fall können wir "den Griff" in irgendeiner Warteschlange, ermöglicht es uns immer noch zurückhalten, Griff es und somit in der Lage sein zu erkennen, wenn ein deadlock tritt auf, nachdem die queue abgeschleudert wird; und wenn es ist, und da haben wir ein handle der queue, die wir zuvor eingestellt haben, konnten wir irgendwie etwas tun, um zu entsperren den deadlock?
Wieder, wenn das ist zu viel zu beantworten, entweder das, oder wenn meine Argumentation ist vollständig ANNULLIERBAR /off hier (in Frage #4), fühlen Sie sich frei, lassen Sie diesen Teil unbeantwortet.
Glückliches Neues Jahr.
@san.t
Mit static void *myFirstQueue = 0;
Wir dies tun:
dispatch_queue_set_specific(firstQueue, &myFirstQueue, &myFirstQueue, NULL);
Völlig verständlich.
Aber wenn wir das tun:
static void *myFirstQueue = 1;
//or any other number other than 0, it would be OK to revert back to the following?
dispatch_queue_set_specific(firstQueue, myFirstQueue, (void*) myFirstQueue, NULL);
Über dispatch_once_t
:
Können Sie erläutern, wie mehr dazu:
Warum muss dispatch_once_t
ersten sein 0, und wie und warum würde er so tun müssen, als einen boolean zu einem späteren Zeitpunkt? Hat das mit Erinnerung zu tun /Sicherheit oder die Tatsache, dass die Vorherige Speicheradresse besetzt war, die durch andere Objekte wurden nicht 0 (nil
)?
Wie bei Frage #3:
Sorry, da ich vielleicht nicht ganz klar: habe ich das nicht gemeint ich bin in eine Sackgasse. Ich meinte, ob oder nicht, kann jemand mir zeigen, ein Szenario im code mit GCD, das führt zu einem deadlock.
Schließlich:
Ich hoffe, Sie Antworten konnte, Frage #4. Wenn nicht, wie bereits erwähnt, ist es OK.
dispatch_get_current_queue
ist veraltet. Es hat sich gezeigt, dass ernsthafte zugrunde liegenden Probleme. Es ist nicht sicher. Benutze es nie.- Ich bin verwirrt, warum Sie überprüfen, welche Warteschlange Sie gleich nach Sie haben explizit ausgelöst, der block auf die Warteschlange. Sie müssen eine solche Prüfung vor dem Versand nicht nach, wie ich versuchte, dies zu tun in meinem helper-Funktion in dieser Frage: stackoverflow.com/questions/12806506/... . Möchten Sie vielleicht zu Lesen Rob ' s Antwort, und einige der Kommentare darunter ist es für einige subtile Unterschiede zwischen den veralteten
dispatch_get_current_queue()
unddispatch_get_specific()
. - Ich bin nicht so wirklich; es dient nur als ein Beispiel für mich zu Fragen, in Frage. Danke für den link; wird auf jeden Fall Lesen.
- Apple hat sich sehr klar in einem Ihrer WWDC-videos darüber, warum Sie veraltet
dispatch_get_current_queue
. Die details sind kompliziert. Dies ist threading im kernel-Ebene, nachdem alle. Aber der Punkt ist, diese Besondere Missbilligung ist nicht nur ein "serviervorschlag". Es ist ernst. - Winken das Problem Weg, als "es ist kompliziert" tut Programmierer einen Bärendienst, denke ich. Die konzeptionelle Mängel der rekursive sperren sind in der Tat subtil, aber verstehen Sie, wirft Sie eine Tonne von Licht auf, wie zu tun, concurrent programming effektiv.
- Es gibt keine Notwendigkeit, Welle entfernt - die Nutzlosigkeit von
dispatch_get_current_queue
ist leicht zu erklären: Es gibt keine einheitliche Antwort auf die Frage "was Warteschlange bin ich momentan auf?" in den Allgemeinen Fall. Dispatch-Warteschlangen sind eine Hierarchie, die Böden in einer Reihe von undurchsichtigen, globalen Warteschlangen. Es können auch beliebige Warteschlange Hierarchien gebaut mitdispatch_set_target_queue.
Wenn Sie wissen möchten, wenn Sie auf die Haupt-queue verwenden[NSThread isMainThread]
. Wenn Sie versuchen, verwenden Sie Warteschlangen zu implementieren rekursive sperren, einfach aufhören. Warteschlangen und sperren sind zwei verschiedene Dinge. - FWIW, ich habe erklärt
dispatch_get/set_specific
im detail hier: stackoverflow.com/questions/19833744/... ich habe auch Taube in großem detail auf die null-ness-Anforderungendispatch_once_t
hier: stackoverflow.com/questions/19832150/...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ersten, ich glaube wirklich nicht, Sie sollen machen, dass die Warteschlange gleichzeitigen.
dispatch_sync()
ing zu einer gleichzeitigen Warteschlange ist nicht wirklich viel von irgendetwas (concurrent queues garantieren nicht die Bestellung zwischen den Blöcken ausgeführt werden). So, den rest dieser Antwort davon ausgegangen, dass Sie gemeint haben, eine serielle queue es. Auch ich werde diese Antwort im Allgemeinen, anstatt Ihre spezifischen Fragen; hoffentlich ist das ok 🙂Gibt es zwei grundsätzliche Probleme bei der Verwendung
dispatch_get_current_queue()
diese Weise. Eine sehr breit, die zusammengefasst werden können als "rekursive sperren ist eine schlechte Idee", und ein dispatch-bestimmte eine, können wie folgt zusammengefasst werden "können Sie und oft wird es mehr als einen aktuellen Warteschlange".Problem #1: Rekursive sperren, ist eine schlechte Idee
Den üblichen Zweck einer privaten serielle queue schützen eine invariante des Codes ("invariante" Wesen "etwas, das muss wahr sein"). Zum Beispiel, wenn Sie eine Warteschlange zu schützen der Zugriff auf eine Eigenschaft so ein, dass es thread-safe ist, dann ist die invariante ist ", diese Eigenschaft nicht haben einen ungültigen Wert" (Beispiel: wenn die Eigenschaft ist eine struct, dann ist die Hälfte der struct haben könnte, einen neuen Wert und die Hälfte haben könnte, den alten Wert, wenn es wurde eingestellt von zwei threads auf einmal. Eine serielle Warteschlange Kräfte, ein thread oder der andere um die Einstellung zu beenden die ganze Struktur vor den anderen starten kann).
Können wir ableiten, dass für diesen Sinn zu machen, die invariant zu halten, wenn zu Beginn der Ausführung eines Blocks auf der seriellen queue (sonst, es war eindeutig nicht geschützt). Sobald der block begonnen hat ausgeführt, kann es zu brechen, die die invariante (sagen wir, die Eigenschaft festlegen), ohne Angst vor Unordnung, bis alle anderen threads, solange die invariante hält wieder durch die Zeit, die es gibt (in diesem Beispiel die Eigenschaft hat, vollständig eingerichtet werden).
Zusammenfasst, nur um sicherzustellen, dass Sie sind immer noch folgende: am Anfang und am Ende jedes Blocks auf einer seriellen queue, die invariante, die Warteschlange ist zu schützen, halten müssen. In der Mitte jedes Blockes, kann es gebrochen werden.
Wenn innerhalb des Blocks, nennen Sie etwas, das versucht, die Sache geschützt, die durch die Warteschlange, dann verändert man diese einfache Regel zu einem viel viel mehr kompliziert: statt "am Anfang und am Ende eines jeden Blocks", es ist "am Anfang, am Ende und an jeder Stelle, wo dieser block ruft etwas außerhalb von sich selbst". In anderen Worten, anstatt zu denken, dein thread-Sicherheit auf block-Ebene haben, müssen Sie nun prüfen, jeder einzelnen Zeile von jedem block.
Was hat das zu tun mit
dispatch_get_current_queue()
? Der einzige Grund für die Verwendungdispatch_get_current_queue()
hier ist zu prüfen, "sind wir bereits auf dieser Warteschlange?", und wenn man schon auf die aktuelle Warteschlange dann sind Sie bereits in die beängstigende situation vor!!! So tun Sie das nicht. Verwenden Sie private Warteschlangen zu schützen, die Dinge, und nicht rufen, um anderen code aus in Ihnen. Sollten Sie bereits wissen, die Antwort auf die Frage "bin ich auf diese Warteschlange?" und es sollte "keine".Dies ist der größte Grund
dispatch_get_current_queue()
veraltet: zu verhindern, dass die Menschen, die versuchen zu simulieren rekursive sperren (was ich oben beschrieben) mit.Problem #2: Sie können mehr als eine aktuelle Warteschlange!
Betrachten Sie diesen code:
Klar queueB aktuell ist, aber wir sind auch noch auf queueA!
dispatch_sync
bewirkt, dass die Arbeit auf queueA zu warten, für den Abschluss der arbeiten an queueB, so sind Sie sowohl effektiv als "aktuell".Dies bedeutet, dass dieser code deadlock:
Können Sie auch mehrere aktuelle Warteschlangen durch die Verwendung von target-Warteschlangen:
Was wäre wirklich nötig, hier so etwas wie eine hypothetische "
dispatch_queue_is_synchronous_with_queue(queueA, queueB)
", aber da wäre nur nützlich für die Durchführung der rekursive sperren, und ich habe bereits beschrieben, wie das ist eine schlechte Idee... es ist unwahrscheinlich Hinzugefügt werden.Beachten Sie, dass wenn Sie nur
dispatch_async()
, dann bist du immun gegen deadlocks. Leider, Sie sind nicht immun gegen race conditions.queueB
ZielequeueA
gibt es nicht nur einen Stillstand, sondern die Frage "was Warteschlange bin ich?" ist auch more zweideutig, als es ohnehin schon war. Vielen Dank für kämpfen, den guten Kampf zu Ende umzusetzen versucht rekursive locks mit GCD Warteschlangen. Hoffentlich, wenn es bekommt, erzählt oft genug, genug Orte, die Leute werden aufhören zu versuchen, es zu tun. (Es fällt mir auf, dass rekursiv-Schlösser-mit-GCD ist ein bisschen wie diese generation-version von "double-checked locking is broken." Referenz: cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html )Frage 1:
Die beiden code-Ausschnitt macht das gleiche, ist, dass "einige Arbeit", wenn sich der block ist in der Tat laufen in
firstQueue
. Allerdings sind Sie mit verschiedenen Möglichkeiten, um zu erkennen, es läuft auffirstQueue
der ersten legt man eine nichtNULL
Umfeld ((void*)myFirstQueue
) mit einer bestimmten Taste (myFirstQueue
) und später überprüft, dass der Kontext in der Tat nichtNULL
; der zweite prüft mithilfe der Funktion jetzt veraltetdispatch_get_current_queue
. Die erste ist die bevorzugte Methode. Aber dann scheint es unnötig, michdispatch_sync
garantiert den block zu laufen, infirstQueue
schon.Frage 2:
nur mit
static int * myFirstQueue = 0;
ist nicht ok, diese WeisemyFirstQueue
ist einNULL
Zeiger unddispatch_queue_set_specific(firstQueue, key, context, NULL);
erfordert nichtNULL
key
&context
zu arbeiten. Aber es funktioniert mit kleinen änderungen wie diese:dies würde die Adresse von
myFirstQueue
Variablen als Schlüssel und dem Kontext.Wenn wir das tun:
Ich denke, es wird gut werden, da beide
myFirstQueue
Zeiger nicht aufgelöst werden, vorausgesetzt, die letztendestructor
parameter istNULL
dispatch_once_t
ist auch 0 hat nichts damit zu tun. Es ist 0 in der ersten und nach der es wird ausgelöst, einmal, ist es Wert, der geändert wird, um nicht gleich null ist, im wesentlichen als ein boolean-Wert.Hier sind Auszüge aus
once.h
können Sie sehen, dassdispatch_once_t
ist eigentlich einlong
und dass Apple ' s Implementierung detail erfordert, werden zunächst0
, wahrscheinlich, weil statische & Globale Variablen standardmäßig auf null gesetzt. Und Sie können sehen, dass es eine Zeile:im wesentlichen die überprüfung der
once predicate
ist noch immer auf null, bevor Sie diedispatch_once
Funktion. Es ist nicht die den Speicher betreffen die Sicherheit.Frage 3:
vorausgesetzt, myQueue ist die serielle, parallele Warteschlangen sind ok.
Frage 4: Nicht sicher.