Blöcke und Grand Central Dispatch



Ähnliche Dokumente
Zwischenablage (Bilder, Texte,...)

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Objektorientierte Programmierung

Grundlagen verteilter Systeme

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Lehrer: Einschreibemethoden

Zählen von Objekten einer bestimmten Klasse

teamsync Kurzanleitung

Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten

Bereich METIS (Texte im Internet) Zählmarkenrecherche

4. BEZIEHUNGEN ZWISCHEN TABELLEN

Windows Vista Security

SMS/ MMS Multimedia Center

Einführung in die Programmierung

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss

Installation von Druckern auf dem ZOVAS-Notebook. 1. Der Drucker ist direkt mit dem Notebook verbunden

Stand: Adressnummern ändern Modulbeschreibung

Anleitung zur Daten zur Datensicherung und Datenrücksicherung. Datensicherung

Jederzeit Ordnung halten

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version September

Netzwerkeinstellungen unter Mac OS X

Der Jazz Veranstaltungskalender für Deutschland, Österreich und die Schweiz

Primzahlen und RSA-Verschlüsselung

Gezielt über Folien hinweg springen

Nicht kopieren. Der neue Report von: Stefan Ploberger. 1. Ausgabe 2003

FuxMedia Programm im Netzwerk einrichten am Beispiel von Windows 7

Gruppenrichtlinien und Softwareverteilung

Menü Macro. WinIBW2-Macros unter Windows7? Macros aufnehmen

Anton Ochsenkühn. amac BUCH VERLAG. Ecxel für Mac. amac-buch Verlag

Moni KielNET-Mailbox

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Speicher in der Cloud

4 Aufzählungen und Listen erstellen

Alle Schlüssel-Karten (blaue Rückseite) werden den Schlüssel-Farben nach sortiert und in vier getrennte Stapel mit der Bildseite nach oben gelegt.

STRATO Mail Einrichtung Mozilla Thunderbird

Sichere Anleitung Zertifikate / Schlüssel für Kunden der Sparkasse Germersheim-Kandel. Sichere . der

Anleitung über den Umgang mit Schildern

Persönliche Zukunftsplanung mit Menschen, denen nicht zugetraut wird, dass sie für sich selbst sprechen können Von Susanne Göbel und Josef Ströbl

Mit dem Tool Stundenverwaltung von Hanno Kniebel erhalten Sie die Möglichkeit zur effizienten Verwaltung von Montagezeiten Ihrer Mitarbeiter.

Java Kurs für Anfänger Einheit 5 Methoden

Umzug der abfallwirtschaftlichen Nummern /Kündigung

ACHTUNG: Voraussetzungen für die Nutzung der Funktion s-exposé sind:

Simulation LIF5000. Abbildung 1

iphone- und ipad-praxis: Kalender optimal synchronisieren

ROFIN App Benutzerhandbuch. Version 1.0

Workflows verwalten. Tipps & Tricks

Abschluss Version 1.0

Was ist das Budget für Arbeit?

104 WebUntis -Dokumentation

Zeichen bei Zahlen entschlüsseln

Windows. Workshop Internet-Explorer: Arbeiten mit Favoriten, Teil 1

Speak Up-Line Einführung für Hinweisgeber

C++ Grundlagen. ++ bedeutet Erweiterung zum Ansi C Standard. Hier wird eine Funktion eingeleitet

Dokumentation. Black- und Whitelists. Absenderadressen auf eine Blacklist oder eine Whitelist setzen. Zugriff per Webbrowser

Qualität und Verlässlichkeit Das verstehen die Deutschen unter Geschäftsmoral!

Handout für die Einrichtung von Microsoft Outlook

L10N-Manager 3. Netzwerktreffen der Hochschulübersetzer/i nnen Mannheim 10. Mai 2016

Informationsblatt Induktionsbeweis

Medea3 Print-Client (m3_print)

Handbuch. NAFI Online-Spezial. Kunden- / Datenverwaltung. 1. Auflage. (Stand: )

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten

Das sogenannte Beamen ist auch in EEP möglich ohne das Zusatzprogramm Beamer. Zwar etwas umständlicher aber es funktioniert

Installationsanleitung jk-ma011-1-hotel

NOXON Connect Bedienungsanleitung Manual

Pflegeberichtseintrag erfassen. Inhalt. Frage: Antwort: 1. Voraussetzungen. Wie können (Pflege-) Berichtseinträge mit Vivendi Mobil erfasst werden?

Enigmail Konfiguration

AutoTexte und AutoKorrektur unter Outlook verwenden

Arge Betriebsinformatik GmbH & Co.KG, CAP News 40, Februar CAP-News 40

Erfahrungen mit Hartz IV- Empfängern

Informationen zum neuen Studmail häufige Fragen

Globale Tastenkombinationen für Windows

Wie man Registrationen und Styles von Style/Registration Floppy Disketten auf die TYROS-Festplatte kopieren kann.

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

LEITFADEN ZUR SCHÄTZUNG DER BEITRAGSNACHWEISE

infach Geld FBV Ihr Weg zum finanzellen Erfolg Florian Mock

Hilfedatei der Oden$-Börse Stand Juni 2014

Handbuch für Gründer. Daniela Richter, Marco Habschick. Stand: Verbundpartner:

Inhaltsverzeichnis Seite

1. EINLEITUNG 2. GLOBALE GRUPPEN Globale Gruppen anlegen

Monatstreff für Menschen ab 50 Temporäre Dateien / Browserverlauf löschen / Cookies

Dokumentenverwaltung im Internet

Windows Server 2012 RC2 konfigurieren

Vorgehensweise bei Lastschriftverfahren

1 topologisches Sortieren

Viele Bilder auf der FA-Homepage

Gutes Leben was ist das?

icloud nicht neu, aber doch irgendwie anders

Mandant in den einzelnen Anwendungen löschen

Anleitung zum Computercheck So aktualisieren Sie Ihr Microsoft-Betriebssystem

Nutzerhandbuch Zentrale Klassenverwaltung

Drucken von Webseiten Eine Anleitung, Version 1.0

1 Einleitung. Lernziele. automatische Antworten bei Abwesenheit senden. Einstellungen für automatische Antworten Lerndauer. 4 Minuten.

Bedienungsanleitung: Onlineverifizierung von qualifiziert signierten PDF-Dateien

Dokument Lob erstellen

Hilfen zur Verwendung der Word-Dokumentvorlage des BIS-Verlags

Anleitung Postfachsystem Inhalt

SANDBOXIE konfigurieren

STRATO Mail Einrichtung Microsoft Outlook

Transkript:

Blöcke und Grand Central Dispatch Multithreading ist ein Thema, mit dem sich alle Programmierer bei der modernen Anwendungsentwicklung beschäftigen müssen. Selbst wenn Sie glauben, dass Ihre Anwendung gar kein Multithreading nutzt, tut sie es wahrscheinlich doch, weil die System-Frameworks oft zusätzliche Threads nutzen, um Arbeit vom Thread für die Benutzeroberfläche auszulagern. Es gibt nichts Schlimmeres als eine Anwendung, die hängt, weil dieser Thread blockiert ist. Unter OS X führt das zu dem gefürchteten rotierenden Wasserball, unter ios kann eine Anwendung beendet werden, wenn sie zu lange blockiert ist. Kapitel 6

Kapitel 6 Blöcke und Grand Central Dispatch Zum Glück hat Apple ganz neue Möglichkeiten für das Multithreading eröffnet. Die Kernmerkmale des modernen Multithreadings sind Blöcke und Grand Central Dispatch (GCD). Es handelt sich dabei um zwei verschiedene Technologien, die jedoch gemeinsam eingeführt wurden. Blöcke machen in C, C++ und Objective-C die Verwendung lexikalischer Closures möglich. Sie sind unglaublich nützlich, vor allem, da sie einen Mechanismus bieten, um Code wie Objekte weiterzureichen, sodass er in einem anderen Kontext ausgeführt werden kann. Entscheidend ist dabei, dass Blöcke alles verwenden können, was sich in ihrem Gültigkeitsbereich befindet. GCD ist eine eng damit verbundene Technologie, die eine Abstraktion für das Multithreading auf der Grundlage sogenannter Queues bietet. Blöcke können in diese Queues eingestellt werden, woraufhin GCD die gesamte Zeitplanung übernimmt. Auf der Grundlage der verfügbaren Systemressourcen erstellt diese Einrichtung bei Bedarf Hintergrundthreads zur Verarbeitung der einzelnen Queues, verwendet sie wieder und zerstört sie. Außerdem bietet GCD leicht anzuwendende Lösungen für häufig vorkommende Programmieraufgaben, beispielsweise die threadsichere Einzelcodeausführung und die parallele Ausführung auf der Grundlage der verfügbaren Systemressourcen. Blöcke und GCD bilden die Säulen der modernen Objective-C-Programmierung. Daher müssen Sie genau wissen, wie diese Einrichtungen funktionieren und was sie bieten. Thema 37: Blöcke Blöcke ermöglichen die Nutzung von Closures. Dieses Sprachmerkmal wurde als Erweiterung zum GCC-Compiler eingeführt und steht in allen modernen Versionen von Clang bereit (dem Compilerprojekt für die OS X- und ios-entwicklung). Die erforderliche Laufzeitkomponente für die Verwendung von Blöcken ist in allen Versionen von Mac OS X ab 10.4 und von ios ab 4.0 verfügbar. Technisch gesehen handelt es sich bei Blöcken um ein Merkmal auf C-Ebene, weshalb sie in C-, C++-, Objective-C- und Objective-C++-Code verwendet werden können. Voraussetzung ist nur, dass dieser Code mit einem unterstützten Compiler kompiliert wird und dass die entsprechende Laufzeitumgebung bei der Ausführung vorhanden ist. Grundlagen von Blöcken Ein Block ähnelt einer Funktion, ist aber innerhalb einer anderen Funktion (»inline«) definiert, deren Gültigkeitsbereich er übernimmt. Das Symbol zur 216

Thema 37: Blöcke Anzeige ist ein Zirkumflex, auf den die Implementierung des Blocks in geschweiften Klammern folgt. Ein einfacher Block sieht also wie folgt aus: ^{ // Hier steht die Blockimplementierung Ein Block ist einfach nur ein weiterer Wert mit einem zugehörigen Typ. Ebenso wie ints, floats und Objective-C-Objekte kann ein Block einer Variable zugewiesen und dann wie jede andere Variable verwendet werden. Die Syntax für einen Blocktyp ähnelt der eines Funktionszeigers. Das folgende Beispiel zeigt einen Block, der keine Parameter entgegennimmt und nichts zurückgibt: void (^someblock)() = ^{ // Hier steht die Blockimplementierung Dieser Code definiert eine Variable mit dem Namen someblock. Es mag merkwürdig erscheinen, dass der Variablenname in der Mitte steht, aber wenn Sie erst einmal mit dieser Syntax vertraut sind, lässt sie sich sehr leicht lesen. Die Blocktypsyntax hat folgenden Aufbau: Rückgabetyp (^Blockname)(Parameter) Um einen Block zu definieren, der einen Integer zurückgibt und zwei als Parameter übernimmt, schreiben Sie Folgendes: int (^addblock)(int a, int b) = ^(int a, int b){ return a + b; Ein Block kann wie eine Funktion verwendet werden. Somit können Sie addblock also wie folgt einsetzen: int add = addblock(2, 5); //< add = 7 Die besondere Möglichkeit, die sich bei Blöcken bietet, besteht darin, den Gültigkeitsbereich zu übernehmen, in dem sie deklariert sind. Das bedeutet, dass alle Variablen, die in diesem Bereich verfügbar sind, auch innerhalb des Blocks genutzt werden können. Beispielsweise können Sie wie folgt einen Block definieren, der eine weitere Variable verwendet: int additional = 5; int (^addblock)(int a, int b) = ^(int a, int b){ return a + b + additional; int add = addblock(2, 5); //< add = 12 217

Kapitel 6 Blöcke und Grand Central Dispatch Standardmäßig kann ein Block die in ihm übernommenen Variablen nicht ändern. Würde in unserem Beispiel etwa die Variable additional im Block geändert, so würde der Compiler einen Fehler melden. Es ist allerdings möglich, Variablen mit dem Qualifizierer block als veränderbar zu deklarieren. Damit können Sie beispielsweise einen Block in einer Array-Aufzählung verwenden (siehe Thema 48), um zu ermitteln, wie viele Zahlen in dem Array kleiner sind als 2: NSArray *array = @[@0, @1, @2, @3, @4, @5]; block NSInteger count = 0; [array enumerateobjectsusingblock: ^(NSNumber *number, NSUInteger idx, BOOL *stop){ if ([number compare:@2] == NSOrderedAscending) { count++; ]; // count = 2 Dieses Beispiel zeigt auch die Verwendung eines Inline-Blocks. Der an die Methode enumerateobjectsusingblock: übergebene Block wird nicht einer lokalen Variable zugewiesen, sondern innerhalb des Methodenaufrufs deklariert. Diese häufig genutzte Programmiertechnik macht die Nützlichkeit von Blöcken deutlich. Bevor Blöcke in der Sprache verfügbar waren, hätten Sie bei dem vorstehenden Code einen Funktionszeiger oder Selektornamen übergeben müssen, den die Methode aufrufen kann. Der Status hätte manuell in beide Richtungen übergeben werden müssen, gewöhnlich über einen undurchsichtigen void-zeiger, was jedoch den Code vermehrt und die Methode in gewisser Weise aufgespaltet hätte. Bei der Deklaration eines Inline-Blocks dagegen bleibt die Geschäftslogik an einer Stelle zusammen. Wenn ein Block eine Variable vom Objekttyp übernimmt, behält er sie implizit bei. Die Freigabe erfolgt, wenn der Block selbst freigegeben wird. Das führt zu einer wichtigen Erkenntnis über Blöcke: Ein Block kann selbst als Objekt angesehen werden. Blöcke reagieren auf viele der Selektoren für andere Objective-C- Objekte. Am wichtigsten ist dabei jedoch die Tatsache, dass für einen Block ebenso ein Reference Counting erfolgt wie für andere Objekte. Wird die letzte Referenz auf einen Block entfernt, so wird seine Zuweisung aufgehoben. Dabei werden auch alle in den Block übernommenen Objekte freigegeben, um die Beibehaltungen auszugleichen, die der Block an ihnen vorgenommen hat. Wird ein Block als Instanzmethode einer Objective-C-Klasse definiert, so stehen in ihm die Variable self sowie alle Instanzvariablen der Klasse zur Verfügung. Instanzvariablen sind immer schreibbar und müssen explizit nicht mit block deklariert werden. Wird eine Instanzvariable aber durch einen Lese- oder Schreibvorgang in den Block übernommen, so geschieht dies implizit auch mit der Variable 218

Thema 37: Blöcke self, da sich die Instanzvariable auf die Instanz bezieht. Betrachten Sie als Beispiel den folgenden Block innerhalb einer Methode der Klasse EOCClass: @interface EOCClass - (void)aninstancemethod { //... void (^someblock)() = ^{ _aninstancevariable = @"Something"; NSLog(@"_anInstanceVariable = %@", _aninstancevariable); //... @end Die Variable self bezieht sich auf die Instanz von EOCClass, für die die Methode aninstancemethod ausgeführt wird. Es lässt sich leicht übersehen, dass self in eine solche Art von Block übernommen wird, da die Variable nicht ausdrücklich im Code vorkommt. Der Zugriff auf eine Instanzvariable entspricht aber folgendem Vorgang: self->_aninstancevariable = @"Something"; Aus diesem Grund wird self in den Block übernommen. In den meisten Fällen werden für den Zugriff auf die Instanzvariablen Propertys verwendet (siehe Thema 6), wobei self explizit benutzt wird: self.aproperty = @"Something"; Es ist jedoch wichtig, daran zu denken, dass self ein Objekt ist und bei der Übernahme in den Block beibehalten wird. Dies kann oft zu zyklischen Verweisen führen, wenn der Block selbst wiederum von dem Objekt beibehalten wird, auf das sich self bezieht. Mehr darüber erfahren Sie in Thema 40. Die inneren Mechanismen von Blöcken Jedes Objekt in Objective-C nimmt einen bestimmten Bereich des Arbeitsspeichers ein. Je nach der Anzahl der Instanzvariablen und der enthaltenen zugehörigen Daten fällt die Größe dieses Bereichs für jedes Objekt anders aus. Auch Blöcke sind Objekte, denn bei der ersten Variable in dem Speicherbereich, in dem ein Block definiert ist, handelt es sich um einen Zeiger auf ein Class-Objekt, den sogenannten isa-zeiger (siehe Thema 14). Der Rest des von dem Block belegten Speicherbereichs enthält die Informationen, die für das Funktionieren des Blocks erforderlich sind. Abbildung 6 1 zeigt ausführlich den Aufbau eines Blocks. 219

Kapitel 6 Blöcke und Grand Central Dispatch Abb. 6 1 Aufbau eines Blockobjekts im Arbeitsspeicher Besonders wichtig dabei ist die Variable invoke, ein Funktionszeiger auf die Stelle, an der sich die Implementierung des Blocks befindet. Der Prototyp der Funktion nimmt mindestens einen void*-parameter entgegen, bei dem es sich um den Block selbst handelt. Wie Sie bereits wissen, sind Blöcke eine Vereinfachung für Funktionszeiger, bei denen es notwendig war, den Status über einen undurchsichtigen void-zeiger zu übergeben. Alles, was früher über C-Standardfunktionen erledigt wurde, wird durch den Block jetzt in ein kompaktes, leicht zu verwendendes Benutzerinterface gepackt. Die Variable descriptor ist ein Zeiger auf eine Struktur, die jeder Block hat und die die Gesamtgröße des Blockobjekts und die Funktionszeiger für copy und dispose deklariert. Diese Hilfsfunktionen werden ausgeführt, wenn der Block kopiert bzw. verworfen wird, um dabei die übernommenen Objekte beizubehalten bzw. freizugeben. Außerdem enthält ein Block Kopien aller von ihm übernommenen Variablen. Sie werden hinter der Variable descriptor gespeichert und nehmen so viel Platz ein, wie jeweils erforderlich ist. Das bedeutet nicht, dass die Objekte selbst kopiert werden, sondern nur die Variablen, die Zeiger festhalten. Wird der Block ausgeführt, werden die übernommenen Variablen in diesem Bereich des Arbeitsspeichers gelesen. Das ist der Grund, aus dem der Block als Parameter an die Funktion invoke übergeben werden muss. 220

Thema 37: Blöcke Globale, Stack- und Heap-Blöcke Bei der Definition eines Blocks wird der von ihm eingenommene Bereich des Arbeitsspeichers auf dem Stack zugewiesen. Das bedeutet, dass der Block nur innerhalb des Gültigkeitsbereichs gültig ist, in dem er selbst definiert wurde. Folgender Code ist beispielsweise gefährlich: void (^block)(); if ( /* irgendeine Bedingung */ ) { block = ^{ NSLog(@"Block A"); else { block = ^{ NSLog(@"Block B"); block(); Die beiden innerhalb der if- und der else-anweisung definierten Blöcke werden auf dem Stack zugewiesen. Am Ende des Gültigkeitsbereichs kann der Compiler den betreffenden Arbeitsspeicher wieder überschreiben. Jeder Block ist also nur innerhalb des zugehörigen Abschnitts der if-anweisung garantiert gültig. Der Code wird zwar ohne Fehler kompiliert, aber es ist nicht sicher, ob er zur Laufzeit funktioniert oder nicht. Wird der ausgewählte Block nicht durch anderen Code überschrieben, so kann dieses Beispiel ausgeführt werden, anderenfalls tritt ein Absturz auf. Als Lösung für dieses Problem können Sie einem Block die Nachricht copy senden, um ihn vom Stack auf den Heap zu kopieren. Anschließend kann der Block auch außerhalb des Gültigkeitsbereichs verwendet werden, in dem er definiert wurde. Nachdem die Kopie auf dem Block erstellt wurde, wird für sie ein Reference Counting durchgeführt. Bei allen nachfolgenden Kopiervorgängen wird keine neue Kopie erstellt, sondern einfach der Referenzzähler erhöht. Gibt es keine Verweise mehr auf einen Heap-Block, muss er freigegeben werden entweder automatisch (unter ARC) oder durch einen expliziten Aufruf von release (bei manuellem Reference Counting). Sinkt der Zählerstand auf 0, so wird die Zuweisung des Heaps-Objekts aufgehoben wie bei jedem anderen Objekt auch. Ein Stack-Block muss nicht explizit freigegeben werden, da der Arbeitsspeicher auf dem Stack automatisch neu belegt wird was der Grund dafür ist, dass der Code in dem vorherigen Beispiel so gefährlich war. Damit können Sie den zuvor gezeigten Code mit zwei Aufrufen der Methode copy sicher machen: 221

Kapitel 6 Blöcke und Grand Central Dispatch void (^block)(); if ( /* irgendeine Bedingung */ ) { block = [^{ NSLog(@"Block A"); copy]; else { block = [^{ NSLog(@"Block B"); copy]; block(); Jetzt ist der Code sicher. Bei manuellem Reference Counting müsste der Block noch freigegeben werden, sobald er nicht mehr benötigt wird. Eine weitere Kategorie neben den Stack- und den Heap-Blöcken bilden die globalen Blöcke. Blöcke, die keinen Status übernehmen, also z. B. keine Variablen aus dem umschließenden Gültigkeitsbereich, benötigen auch keinen bestimmten Status zur Ausführung. Der gesamte Speicherbereich, den diese Blöcke verwenden, ist zur Kompilierungszeit bekannt. Daher werden globale Blöcke im globalen Arbeitsspeicher erstellt, anstatt sie jedes Mal, wenn sie benötigt werden, auf dem Stack anzulegen. Das Kopieren eines globalen Blocks ist eine leere Operation, und die Zuweisung eines globalen Blocks wird auch niemals aufgehoben. Letzten Endes handelt es sich bei solchen Blöcken um Singletons. Das folgende Beispiel zeigt einen globalen Block: void (^block)() = ^{ NSLog(@"This is a block"); Alle zur Ausführung dieses Blocks erforderlichen Informationen sind zur Kompilierungszeit bekannt, weshalb er als globaler Block eingerichtet werden kann. Dabei handelt es sich lediglich um eine Optimierung, um unnötigen Aufwand zu vermeiden, denn wenn ein so einfacher Block wie einer seiner komplizierteren Vettern behandelt würde, fielen beim Kopieren und Verwerfen zusätzliche Arbeiten an. Was Sie sich merken sollten Blöcke sind lexikalische Closures für C, C++ und Objective-C. Blöcke können optional Parameter entgegennehmen und Werte zurückgeben. Blöcke können auf dem Stack, auf dem Heap oder global zugewiesen werden. Ein Block auf dem Stack lässt sich auf den Heap kopieren, wo er wie die Standardobjekte von Objective-C einem Reference Counting unterliegt. 222