Vorlesung Echtzeitbetriebssysteme VI. Posix Übung

Slides:



Advertisements
Ähnliche Präsentationen
der Universität Oldenburg
Advertisements

Operating Systems Principles
10.2 Wechselseitiger Ausschluss in Hardware
Agenda Sitzung 2 für den Programmaufbau
WS 04/05, v 1.0Communication Networks I - Overview and Formalities1 Lösung von Reader-Writer bei Reader-Bevorzugung int Readernr=0; Semaphor w, mutex=1.
Institut für Angewandte Mikroelektronik und Datentechnik Fachbereich Elektrotechnik und Informationstechnik, Universität Rostock Vorlesung Echtzeitbetriebssysteme.
Fakultät für informatik informatik 12 technische universität dortmund Universität Dortmund Middleware Peter Marwedel TU Dortmund, Informatik 12 Germany.
Threadnocchio Dietrich Boles Nachdenken in Aurich 2009
Prof. Dr.-Ing. habil. B. Steinbach - Informatik / Softwaretechnologie und Programmierungstechnik - Institut für Informatik F Verteilte Software - Java.
Kapitel 6.1 Nebenläufigkeit und wechselseitiger Ausschluss
Kapitel 7.2 Dining philosophers problem
Java: Objektorientierte Programmierung
Java: Grundlagen der Objektorientierung
Strukturen. In einer Struktur kann eine beliebige Anzahl von Komponenten (Daten) mit unterschiedlichen Datentypen (im Gegensatz zu Feldern) zusammengefaßt.
1 Named Pipes alias FIFO Haben einen Eintrag im Dateisystem und sind somit durch Zugriffsrechte identifizierbar Ermöglichen die Kommunikation zwischen.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Kapitel 3 Claudio Moraga, Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
Institut für Angewandte Mikroelektronik und Datentechnik Fachbereich Elektrotechnik und Informationstechnik, Universität Rostock Spezielle Anwendungen.
MD, Entwicklung von Powerpointfolien Institut für Angewandte Mikroelektronik und Datentechnik Fachbereich Elektrotechnik und Informationstechnik, Universität.
Institut für Angewandte Mikroelektronik und Datentechnik Fachbereich Elektrotechnik und Informationstechnik, Universität Rostock Vorlesung Echtzeitbetriebssysteme.
Operating Systems Principles
Modulare Programmierung
DVG Verkettete Listen Verkettete Listen. DVG Verkettete Listen 2 Primitive Datentypen Vorteile: –werden direkt vom Prozessor unterstützt.
15.1 Synchronisation nebenläufiger Prozesse
Wir müssen also überlegen: Implementierung der Knoten, Implementierung der Kanten, daraus: Implementierung des Graphen insgesamt. Annahme: die Knoteninhalte.
FH-Hof Sortieren mit Binären Bäumen Richard Göbel.
Haben – to have ich habe du hast er/sie hat es hat man hat wir haben
© A. Schwing, 2010Institute of Visual Computing Informatik I for D-MAVT Exercise Session 10.
Zu + Infinitiv : eine Erklärung
Medien zwischen Technologie und Gesellschaft Dozent: Herr Prof. Dr. Manfred Thaller SS 13 Referent: Christian Braun.
Loops Jason Gregory : Game Engine Architecture Tobias Kemper Softwaretechnologie II (Teil 2) HKI Uni Köln SS 2013.
Prozess-synchronisation
OO implementieren Teil IV Objekte erzeugen. © René ProbstModul 226IV - 2 Von der Klasse zum Objekt Plan Bau Objekt Klasse Instanzierung Objekt Das Objekt.
Einführung in die Programmiersprache C 3.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
der Imperativ Nicht Vergessen! (Don’t forget)
Modal sheet Tick list Mark scheme Connectives Question sheet Exemplar graded texts.
Parallel Programming Thread Synchronization. Heute 1. Lösung zu Assignment 2 2. Erstellen und Starten von Threads in Java 3. Das synchronized Schlüsselwort.
Parallel Programming Proofs ( yay !)
Parallel Programming ( J ) CSP
I want to see Ich will sehen.
Algorithmen und Datenstrukturen Übungsmodul 6
University of Applied Sciences Übung Objektorientierte Programmierung II Dipl.-Inf. (FH) Markus Vogler.
Real Time Operating System
Dynamische Datentypen
Verben Wiederholung Deutsch III Notizen.
Travelling Salesman Problem (TSP)
Thread Synchronisation in JAVA
Betriebssysteme Übung 2. Tutorium. Task 1 – Locks (1) Wozu Locks? Dienen dazu, exklusiven Zugriff auf eine Ressource sicherzustellen Lock = binäre Semaphore.
Learning By Doing Parallelverarbeitung Multithreading (Nebenläufigkeit) Alte Idee der Parallelverarbeitung statt rein sequentieller Prozesse Parallelverarbeitung.
Separable Verbs Turn to page R22 in your German One Book R22 is in the back of the book There are examples at the top of the page.
1 Intern | ST-IN/PRM-EU | | © Robert Bosch GmbH Alle Rechte vorbehalten, auch bzgl. jeder Verfügung, Verwertung, Reproduktion, Bearbeitung,
Launch ON Global.vi System ID object name classname Services to suscribe Observer Control Ref vi-path Service name Step 1 : Objects register to the Global.vi´s,
JOURNEY TO A DIFFERENT SPEAKING WORLD Cookie Halbritter July 8, 2003.
Proseminar Java Threads. Deadlock und Fairness 1. Deadlock 2. Lockstarvation.
Java Thread Scheduling Jin Zhou Proseminar Java Thread Scheduling November 2000.
Beispielanwendung von Java Threads
THE CONVERSATIONAL PAST
GWDG – Kurs Parallelrechner-Programmierung mit MPI MPI Punkt-zu-Punkt-Kommunikation Oswald Haan
Alois Schütte Advanced System Programming 2 Interprozeßkommunikation  2.1 JVM Ablaufumgebung  2.2 Java Native Interface (JNI)  Verwendung von.
Echtzeitbetriebssysteme Übungen
Java-Kurs - 4. Übung Hausaufgabe Weitere Kontrollstrukturen
Parallel Programming Semaphores / Reader - Writer - Lock
Java Programme nur ein bisschen objektorientiert.
© 2008 TravelTainment The Amadeus Leisure Group Thread-Programmierung im Qt-Framework Von: Simon Lubberich Erstbetreuer:
Center for Biotechnology Bielefeld Bioinformatics Service Netzwerk - Programmierung Threads Alexander Sczyrba Jan Krüger.
Netzwerk - Programmierung
Echtzeit-Betriebssysteme
Aufgaben Semaphore Übersicht (Dijkstra)
Implementieren von Klassen
 Präsentation transkript:

Vorlesung Echtzeitbetriebssysteme VI. Posix Übung Dr.-Ing. Frank Golatowski

Ziele der Vorlesung Erzeugung von Threads Diskussion von Synchronisationsproblemen Anwendung von: Semaphoren Mutex Condition Variablen

Prozesse vs. Threads Kein Speicherschutz innerhalb eines Prozesses Kommunikation mit anderen Prozessen nur über Betriebssystem oder „Shared Memory“

Thread erzeugen pthread_create(thread_id, attr, func, args) pthread_t pthread_self() Aufruf gibt den eigenen Thread-ID zurück pthread_yield(); informiert den Scheduler, dass der Thread sein Zeitquantum abbrechen will. pthread_exit(status) pthread_join(pthread_id) pthread_detach() Die Exit-Struktur des Threads wird nicht weiter benötigt, durch nachfolgenden pthread_join- Aufrufe. pthread_t me; me = pthread_self(); pthread_t thread; pthread_detach(thread);

pthread_create Benötigt vier Argumente Threadvariable für den Thread Threadattribute Startadresse für den Thread Ein Argument für den Thread pthread_t thread_id; pthread_attr_t attr; void thread_function (void *argument); char *some_arguments pthread_create(thread_id, attr, func, args)

Thread Attribute Festlegen von Eigenschaften des Threads in Struktur pthread_attr_t Stacksize Priorität Schedulingverhalten Eigenschaften werden grundsätzlich über Funktionen gesetzt. Initialisierung der Attribut-Struktur vor Benutzung unbedingt erforderlich Beispiel: pthread_attr attr; pthread thread; pthread_attr_init(&attr); pthread_attr_setcpu_np(&attr, 0); pthread_attr_setschedpolicy( &attr, SCHED_RR); pthread_attr_setstacksize(&attr, 20000); pthread_create(&thread, &attr, function, 0 );

Hello world void print_message_function( void *ptr ); main() { pthread_t thread1, thread2; char *message1 = "Hello"; char *message2 = "World"; pthread_create( &thread1, pthread_attr_default, (void*)&print_message_function, (void*) message1); pthread_create(&thread2, pthread_attr_default, (void*)&print_message_function, (void*) message2); exit(0); } void print_message_function( void *ptr ) char *message; message = (char *) ptr; printf("%s ", message);

Aufgaben Entwickeln Sie ein Programm „Hello World“, das zwei Threads erzeugt. Der erste Thread soll die Ausgabe „Hello“ und der zweite die Ausgabe „World“ machen. Experimentieren Sie mit unterschiedlichen Ausschriften, z.B. Calling thread : „Ich habe gerade 2 Threads erzeugt!“ Thread 1 : „Ich bin Thread 1 und habe die Aufgabe, die Ausgabe ‚Hello‘ zu machen“ Starten Sie das Programm mehrmals! Nutzen Sie die Online-Dokumentation im Verzeichnis /home/bj74/vorlesung/bs/help!

Diskussion des vorherigen Beispiels Ist die Reihenfolge der Ausschriften gesichert? Hat die Länge der Ausschriften Einfluss auf das Verhalten? Was passiert, wenn der erzeugenden Thread sich vor den Threads mit exit(0) beendet. Welches sind die zwei Wettlaufbedingungen in dem Programm.

Hello World, Versuch II Ein Workaround zur Lösung der Wettlaufbedingungen. Vor dem Erzeugen des zweiten Threads und vor dem Aufruf der exit-Funktion eine kleine Verzögerung einfügen.

Hello World, Versuch II void print_message_function( void *ptr ); main() { pthread_t thread1, thread2; char *message1 = "Hello"; char *message2 = "World"; pthread_create( &thread1, pthread_attr_default, (void*)&print_message_function, (void*) message1); sleep(10); pthread_create(&thread2, pthread_attr_default, (void*)&print_message_function, (void*) message2); exit(0); } void print_message_function( void *ptr ) char *message; message = (char *) ptr; printf("%s ", message);

Diskussion War das gut?

Diskussion Es ist niemals sicher, sich auf Zeitverzögerungen zu verlassen, um eine Synchronisation durchzuführen Die Wettlaufbedingungen sind die gleichen wie bei parallelen Prozessen, die sich eine Ressource teilen. Ressource ist hier <stdout>. Mit sleep() wurde ein regelrechter Schnitzer eingefügt: sleep() u. exit() sind Systemrufe, die prozess-spezifisch sind D.h. mit sleep() geht der ganze Prozess schlafen. So dass folglich die gleiche Situation vorherrscht, wie in dem Beispiel ohne sleep().

Synchronisation zwischen Erzeuger und den kreierten Threads pthread_t some_thread; int exit_value; int *exit_status=&exit_value; // do something // create thread // work with thread // exit now pthread_join( some_thread, &exit_status ); Aufrufender Thread wird suspendiert, bis angegebener Thread terminiert Synchronisation möglich, sinnvoll vor allem für exit() Auswertung des Rückgabewertes möglich

Verzögerung eines Threads pthread_delay_np (np = not portable) struct timespec delay; delay.tv_sec = 2; delay.tv_nsec = 0; pthread_delay_np( &delay )

Synchronisation: Mutex Using A Mutex: Accessing Shared Data  In einem multithreaded Programm müssen alle gemeinsam genutzten Daten, durch Anwendung von Mutexen geschützt werden. Nur derjenige Prozess, der im Besitz eines Mutexes ist (es belegt hat), hat Zugriff auf eine gemeinsam genutzte Ressource.

Mutex THREAD1 THREAD2 lock Mutex lock Mutex update Data update Data Unlock Mutex THREAD2 lock Mutex update Data Unlock Mutex Mutex Daten Zustand

Mutex-Funktionen Mutexe sichern den Zugang zum kritischen Abschnitt Posix-Funktionen: pthread_mutex_init(sem, init) pthread_mutex_lock (sem) pthread_mutex_trylock(sem) pthread_mutex_unlock (sem) pthread_mutex_destroy (sem) Achtung: Mutex-Funktionen immer paarweise in möglichst kurzen und übersichtlichen Abschnitten benutzen

Mutex Mutex ist eine einfache (speicherlose) Semaphore pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int pthread_mutex_init ( … ); int pthread_mutex_destroy ( … ); Mutex verwenden: int pthread_mutex_lock ( … ); int pthread_mutex_trylock ( … ); int pthread_mutex_unlock ( … );

Beispiel: Puffer mit einem Element. Synchronisation mit Mutex void reader_function(void); void writer_function(void); char buffer; int buffer_has_item = 0; pthread_mutex_t mutex; struct timespec delay; main() { pthread_t reader; delay.tv_sec = 2; delay.tv_nsec = 0; pthread_mutex_init(&mutex, pthread_mutexattr_default); pthread_create( &reader, pthread_attr_default, (void*)&reader_function,NULL); writer_function(); }

Beispiel: Puffer mit einem Element. Synchronisation mit Mutex void writer_function(void) { while(1) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 0 ) buffer = make_new_item(); buffer_has_item = 1; } pthread_mutex_unlock( &mutex ); pthread_delay_np( &delay ); void reader_function(void) { while(1) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 1) consume_item( buffer ); buffer_has_item = 0; } pthread_mutex_unlock( &mutex ); pthread_delay_np( &delay );

Was passiert, wenn pthread_delay_np() nicht benutzt wird? Mutex Mutex hat nur zwei Zustände: lock und unlock Entspricht einem binären Semaphor. POSIX-Mutexe können mit Condition Variable sinnvoll kombiniert werden. Z.B. derart dass ein Thread, der einem Mutex blockiert, auch auf ein Signal von einem anderen Thread warten kann. Wenn das Signal eintrifft, kann der blockierte Thread aufgeweckt werden und kann versuchen, das relevante Mutex zu belegen Was passiert, wenn pthread_delay_np() nicht benutzt wird?

Aufgabe Entwickeln Sie ein Programm, das Asciizeichen von <stdin> einliest. Der Asciicode dieser Zeichen soll in einem zuvor erzeugten Thread ‚reader‘ ausgegeben werden. Wie können die Threads synchronisiert werden? Welche Probleme treten auf?

Diskussion Puffer kann nur ein Element aufnehmen Schnellerer Thread wird auf Geschwindigkeit des langsameren abgebremst Verschwendung von Rechenzeit durch Pollen von buffer_has_item Abbruchfunktionen fehleranfällig/kritisch: void writer_function(void) { char a; while( a != 'q' ) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 0 ) a = make_new_item(); buffer=a; if ( a != 'q' ) buffer_has_item = 1; } pthread_mutex_unlock( &mutex ); void writer_function(void) { while( 1 ) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 0 ) buffer = make_new_item(); if ( buffer =='q' ) break; buffer_has_item = 1; } pthread_mutex_unlock( &mutex ); void writer_function(void) { while( 1 ) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 0 ) buffer = make_new_item(); buffer_has_item = 1; } pthread_mutex_unlock( &mutex ); if ( buffer =='q' ) break; Linkes Beispiel: Funktion wird im kritischen Abschnitt beendet. Unlock fehlt Mittleres Beispiel:

Abbruchprobleme void reader_function(void) { while( 1 ) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 1) consume_item(buffer); buffer_has_item = 0; } pthread_mutex_unlock( &mutex ); if ( buffer==‘q‘ ) break; void reader_function(void) { char a; while( 1 ) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 1) a=buffer; if ( a != 'q' ) consume_item(a); buffer_has_item = 0; } pthread_mutex_unlock( &mutex ); void reader_function(void) { char a=0; while( a!= 'q' ) pthread_mutex_lock( &mutex ); if ( buffer_has_item == 1) a=buffer; if ( a != 'q' ) consume_item(a); buffer_has_item = 0; } pthread_mutex_unlock( &mutex ); Linkes Beispiel: Benutzt buffer(Variable des kritischen Abschnitts nach unlock Mittleres Beispiel: Muss unsauber durch vaterthread beendet werden, da Endlossschleife Rechtes Beispiel: ist i.o.

Condition Variable Using A Condition Variable: Scheduling Shared Ressources  Wird verwendet, wenn der Programmierer die Art, wie mehrere Threads auf gemeinsam genutzte Ressourcen zugreifen, beeinflussen will und der typische „Einer-Pro-Zeit“-Gegenseitige Ausschluß nicht ausreicht.

Condition Variable while (! predicate_on_condition (s)) pthread_cond_wait (&s, &v); Wird verwendet, um auf das Eintreffen bestimmter Ereignisse zu warten. Es können Informationen übertragen werden, die Auskunft über den Zustand gemeinsam genutzter Daten geben. Ist (im allgemeinen) mit einer einzelnen Bedingung für einer Zustandskomponente verbunden Ist verbunden mit einem Mutex, der den Zugriff auf die Zustandskomponente steuert. Mutex CV1 CV2 Daten Zustand

Condition Variable THREAD1 while (P1) wait CV1 Do A1 THREAD3 while (P1) wait CV1 Do B1 Mutex CV1 CV2 Daten Zustand THREAD2 while (P2) wait CV2 Do A2 THREAD4 while (P2) wait CV2 Do B2 THREAD5 update state broadcast CV1 signal CV2

Condition Variable Eine CV ist immer mit einem bestimmten Mutex verbunden. Und mit den Daten, die durch das Mutex geschützt sind. Monitorkonzept wird damit realisierbar Ein Monitor besteht aus einem Mutex, Daten und keiner, einer oder mehrerer Bedingungen Es gibt drei Operationen: Wait Signal Broadcast

Condition Variablen - Operationen Wait (pthread_cond_wait) : Signal (pthread_cond_signal) : Broadcast (pthread_cond_broadcast) : TimedWait (pthread_cond_timedwait) : s.S.5 DEC-Paper

Beispiel mit Conditions REACTOR lock state.m while pred (state.data) { wait state.cv } if pred (stat.data) { do actions; unlock state.m ACTOR lock state.m update state.data unlock state.m signal state.cv Mutex CV1 CV2 Daten Zustand

Beispiel mit Conditions Dbuff - Example

Beispiel mit zählendem Semaphor Keine Verschwendung von Rechenzeit zählendes Semaphor void reader_function(void); void writer_function(void); char buffer; // ohne Verzögerung (s. Mutexsample) Semaphore writers_turn; Semaphore readers_turn; main() { pthread_t reader; semaphore_init( &readers_turn ); semaphore_init( &writers_turn ); /* writer must go first */ semaphore_down( &readers_turn ); pthread_create( &reader, pthread_attr_default, (void*)&reader_function,NULL); writer_function(); }

Beispiel mit zählendem Semaphor void writer_function(void) { while(1) semaphore_down( &writers_turn ); buffer = make_new_item(); semaphore_up( &readers_turn ); } void reader_function(void) { while(1) semaphore_down( &readers_turn ); consume_item( buffer ); semaphore_up( &writers_turn ); } Sieht übersichtlicher aus.

Aufgabe zu Semaphoren Entwickeln Sie ein Programmm, das zwei Threads „Writer“ und „Reader“ erzeugt. Die Kommunikation zwischen den Threads soll über zählende Semaphoren gelöst werden. Der „Writer“ hat die Aufgabe, eine stetig steigende Integerzahl nach Buffer zu schreiben. Zu beachten ist, dass Buffer eine Variable im kritischen Abschnitt ist! Der „Reader“ soll diese Variable lesen und den Ascii-Code sowie das entsprechende Zeichen ausgeben. Alle Threads sollen sich definiert beenden, wenn Buffer den Wert ‘q‘=112 erreicht hat.

Hello World mit zählendem Semaphor Semaphore child_counter; Semaphore worlds_turn; main() { pthread_t thread1, thread2; char *message1 = "Hello"; char *message2 = "World"; semaphore_init( &child_counter ); semaphore_init( &worlds_turn ); semaphore_down( &worlds_turn ); // world goes second // child_counter now must be up-ed 2 times for a thread blocked on it to be released semaphore_decrement( &child_counter ); // value now 0 semaphore_decrement( &child_counter ); // value now -1 pthread_create( &thread1, pthread_attr_default, void *) &print_message_function, (void *) message1); semaphore_down( &worlds_turn ); pthread_create(&thread2, pthread_attr_default, (void *) &print_message_function, (void *) message2); semaphore_down( &child_counter ); // not really necessary to destroy since we are exiting anyway semaphore_destroy ( &child_counter ); semaphore_destroy ( &worlds_turn ); exit(0); }

Hello World mit zählendem Semaphor void print_message_function( void *ptr ) { char *message; message = (char *) ptr; printf("%s ", message); fflush(stdout); semaphore_up( &worlds_turn ); semaphore_up( &child_counter ); pthread_exit(0); }

Deadlock und Liveness Livelock: Prozesse, die für immer busy sind, auf ein spin lock wartend. Deadlock: Prozesse, die für immer suspendiert (schlafend) an einer Condition variable oder einer Lock-Operation sind. Starvation: Prozesse, die für unbestimmte Zeit aufgeschoben sind. Liveness: Prozesse, die frei von Deadlock, Livelock und Starvation sind

Sema, Mutex, CV Mit allen kann man sehr leicht Deadlocks produziert werden Es gibt einige Regeln, um Deadlock-Situationen zu reduzieren und einen sensiblen Gebrauch von Semaphor, Mutex und CV zu sichern. Eine Möglichkeit, um Deadlocks zu verhindern ist z.B. die Verwendung des Priority Ceiling Protocols

Wie viele und wie groß Mutexe können einzelne Daten oder Programmbereiche schützen Wie dick sollte ein Mutex (d.h. der geschützte Bereich) sein? Wie viele Zustandsvariablen sollten kombiniert werden und durch ein Mutex geschützt werden. Mutexes bewirken, dass Threads warten. Das hat „Kontext switch“ zur Folge, der Zeit kostet. Wenige und große Mutexe sind gut.

Speisende Philosphen mit Mutexe

Aufgabe Auf der Basis von Posix-Mutexe und Posix-Conditions zählende Semaphore implementieren.

Fehlerbehandlung nie vergessen! pthread_t some_thread; if ( pthread_create( &some_thread, ... ) == -1 ) { perror("Thread creation error"); exit(1); }

Thread beenden Beschreibung Funktion Beschreibung pthread_cancel (thread_id) pthread_setcancelstate(stat, old) pthread_setcanceltype(typ, old) THREAD_CANCEL_ENABLE, THREAD_CANCEL_DISABLE pthread_testcancel() pthread_join pthread_cond_wait pthread_cond_timed_wait phread_testcancel sigwait Sem_wait

Thread terminieren Pthread_cleanup_push(func, arg) Pthread_cleanup_pop(exec) sigwait Sem_wait