• Keine Ergebnisse gefunden

Konzepte der Nebenl¨ aufigkeit

N/A
N/A
Protected

Academic year: 2022

Aktie "Konzepte der Nebenl¨ aufigkeit"

Copied!
3
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 01.12.09:

Grundlagen der Nebenl¨ aufigkeit in Haskell

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen ITeil II: Fortgeschrittene Datenstrukturen ITeil III: Nebenl¨aufigkeit

I Grundlagen

I Abstraktionen und Ausnahmebehandlung

I Software Transactional Memory ITeil IV: The Future of Programming

2

Heute gibt’s hier

Nebenl¨aufigkeit

IGrundkonzepte

IImplementation in Haskell

IBasiskonzepte

3

Konzepte der Nebenl¨ aufigkeit

I Thread (lightweight process) vs. Prozess Programmiersprache/Betriebssystem Betriebssystem (z.B. Java, Haskell, Linux)

gemeinsamerSpeicher getrennterSpeicher

Erzeugungbillig Erzeugungteuer

mehrereproProgramm einerproProgramm

IMultitasking:

I pr¨aemptiv:Kontextwechsel wirderzwungen

I kooperativ:Kontextwechsel nurfreiwillig

4

Zur Erinnerung: Threads in Java

IErweiterung der KlassenThreadoderRunnable IGestartet wird Methoderun()— durch eigene ¨uberladen IStarten des Threads durch Aufruf der Methodestart() IKontextwechsel mityield()

IJe nach JVM kooperativoderpr¨aemptiv.

ISynchronisation mitsynchronize

5

Threads in Haskell: Concurrent Haskell

ISequentiellesHaskell: Reduktion eines Ausdrucks

I Compiler legt Reihenfolge fes (outermost leftmost — verz¨ogerte Auswertung)

INebenl¨aufigesHaskell: Reduktion eines Ausdrucks anmehreren Stellen Ighcundhugsimplementieren Haskell-Threads

Ighc:pr¨aemptiv,hugs:kooperativ

IModulControl.Concurrententh¨alt Basisfunktionen IWenige Basisprimitive, darauf aufbauend Abstraktionen

6

Wesentliche Typen und Funktionen

IJeder Thread hat einen Identifier: abstrakter TypThreadId INeuen Thread erzeugen:forkIO:: IO()-¿ IO ThreadId IThread stoppen:killThread :: ThreadId -¿ IO () IKontextwechsel:yield :: IO ()

IEigener Thread:myThreadId :: IO ThreadId IWarten:threadDelay :: Int -¿ IO ()

7

Rahmenbedingungen

IZeitscheiben:

I Tick: Default 20ms

I Contextswitchpro Tick bei Heapallokation

I ¨Anderungen perKommandozeilenoptionen:+RTS -V¡time¿ -C¡time¿

IBlockierung:

I Systemaufrufe blockierenalle Threads

I Mit threaded library (-threaded) nicht alle

I Aber: Haskell Standard-IO blockiertnur den aufrufenden Thread

8

(2)

Concurrent Haskell — erste Schritte

IEin einfaches Beispiel:

w r i t e : : Char IO ( )

w r i t e c = putChar c w r i t e c main : : IO ( )

main = f o r k I O ( w r i t e ’X ’ ) w r i t e ’O’

IAusgabeghc: (X|O) IAusgabehugs: (X|O)

9

Synchronisation mit MVars

IBasissynchronisationmechanismusin Concurrent Haskell

I Alles andereabgeleitet

IMVar aver¨anderbareVariable (vgl.IORef a) IEntwederleerodergef¨ulltmit Wert vom Typa IVerhalten beim Lesen und Schreiben

Zustand vorher: leer gef¨ullt

Lesen blockiert(bis gef¨ullt) danach leer Schreiben danach gef¨ullt blockiert(bis leer)

I NB.Aufweckenblockierter ProzesseeinzelninFIFO

10

Basisfunktionen MVars

INeue Variable erzeugen (leer oder gef¨ullt):

newEmptyMVar : : IO (MVar a ) newMVar : : a IO (MVar a )

ILesen:

takeMVar : : MVar a IO a

ISchreiben:

putMVar : : MVar a a IO ( )

11

Abgeleitete Funktionen MVars

INicht-blockierendes Lesen/Schreiben:

tryTakeMVar : : MVar a IO ( Maybe a ) tryPutMVar : : MVar a a IO Bool

I ¨Anderung der MVar:

swapMVar : : MVar a a IO a

withMVar : : MVar a ( a IO b ) IO b modifyMVar : : MVar a ( a IO ( a , b ) ) IO b

I Achtung:race conditions

12

Ein einfaches Beispiel ohne Synchronisation

INebenl¨aufige Eingabe von der Tastatur

import C o n t r o l . Monad( f o r e v e r , r e p l i c a t e M ) import C o n t r o l . Concurrent

echo : : S t r i n g IO ( ) echo p = f o r e v e r $ do

putStrLn ( ” ∗∗∗ P l e a s e e n t e r l i n e f o r ”++p ) l i n e g e t L i n e

nrandomRIO (1 ,100)

r e p l i c a t e M n $ p u t S t r ( p++ ” : ”++ l i n e++” ” ) main : : IO ( )

main = f o r k I O ( echo ”2” ) echo ”1”

IProblem: gleichzeitige Eingabe IL¨osung:MVarsynchronisiert Eingabe

13

Ein einfaches Beispiel mit Synchronisation

IMVarvollEingabe m¨oglich

I Also: initial voll

IInhalt der MVar irrelevant:MVar () echo : : MVar ( ) S t r i n g IO ( ) echo f l a g p = f o r e v e r $ do

takeMVar f l a g

putStrLn ( ” ∗∗∗ P l e a s e e n t e r l i n e ”++ p ) l i n e g e t L i n e

nrandomRIO (1 ,100)

r e p l i c a t e M n $ p u t S t r ( p++ ” : ”++ l i n e++” ” ) putMVar f l a g ( )

main : : IO ( )

main = do f l a g newMVar ( )

f o r k I O ( echo f l a g ”3” ) f o r k I O ( echo f l a g ”2” ) echo f l a g ”1”

14

Das Standardbeispiel

ISpeisende Philosopen

IPhilosophi:

Ivor dem Esseni-tes und(i+1)modn-tes St¨abchen nehmen

Inach dem Essen wieder zur¨ucklegen

ISt¨abchen modelliert alsMVar ()

15

Speisende Philosophen

p h i l o : : [ MVar ( ) ] I n t IO ( ) p h i l o c h o p s t i c k s i = f o r e v e r $ do

l e t num phil = l e n g t h ( c h o p s t i c k s )

−−Thinking:

putStrLn ( ” P h i l #”++ show i ++” t h i n k s . . . ” ) randomRIO (10 , 200)=t h r e a d D e l a y

−−Get ready to eat:

takeMVar ( c h o p s t i c k s ! ! i )

takeMVar ( c h o p s t i c k s ! ! ( ( i +1) ‘mod ‘ num phil ) )

−−Eat:

putStrLn ( ” P h i l #”++ show i ++” e a t s . . . ” ) randomRIO (10 , 200)=t h r e a d D e l a y

−−Done eating:

putMVar ( c h o p s t i c k s ! ! i ) ( )

putMVar ( c h o p s t i c k s ! ! ( ( i +1) ‘mod ‘ num phil ) ) ( )

16

(3)

Speisende Philosophen

IHauptfunktion:nSt¨abchen erzeugen IAnzahl Philosophen in der Kommandozeile

main = do a : getArgs l e t num= read a

c h o p s t i c k s r e p l i c a t e M num $ newMVar ( ) mapM ( f o r k I O . ( p h i l o c h o p s t i c k s ) ) [ 0 . . num1]

b l o c k

IHilfsfunktionblock: blockiert aufrufenden Thread b l o c k : : IO ( )

b l o c k = newEmptyMVar=takeMVar INB: Hauptthread terminiert — Programm terminiert!

17

Abstraktion: Semaphoren

IAbstrakter DatentypQSem

IBetretenkritischer Abschnitt(P):waitQSem :: QSemIO () IVerlassenkritischer Abschnitt(V):signalQSem :: QSemIO () ISemaphore: Z¨ahler plus evtl. wartende Threads

I Perniedrigt Z¨ahler, blockiert ggf. aufrufenden Thread

I Verh¨oht Z¨ahler, gibt ggf. blockierte Threads frei

IImplementierung von Semaphoren mitMVar: eigenes Scheduling IVariation:Quantitative Semaphoren

I Z¨ahler kann um Parameternerh¨oht/erniedrigt werden

18

Semaphoren: die P-Operation

data QSem = QSem (MVar ( Int , [ MVar ( ) ] ) ) IMVar ..f¨ur die ganze Semaphore, darin:

IZ¨ahler der Prozesse im kritischen Abschnitt

IListe von wartenden Prozessen (MVar ()) newQSem : : I n t IO QSem

newQSem n = do mnewMVar ( n , [] ) r e t u r n (QSem m)

19

Semaphoren: die P-Operation

IEintrittin kritischen Abschnitt

IWenn Eintritt m¨oglich, Z¨ahler erniedrigen IAnsonsten blockieren (Reihenfolge!) waitQSem : : QSem IO ( ) waitQSem (QSem sem ) = do

( a v a i l , b l o c k e d ) takeMVar sem i f a v a i l > 0 then

putMVar sem ( a v a i l1, [] ) e l s e do

b l o c k newEmptyMVar

putMVar sem (0 , b l o c k e d++ [ b l o c k ] ) takeMVar b l o c k

20

Semaphoren: die V-Operation

IVerlassendes kritischen Abschnitts IFalls wartende threads, einen aufwecken.

IAlternatives Scheduling:

Iam Anfang hinzuf¨ugen, vom Anfang nehmen (einfacher,unfair)

Iam besten:zuf¨alligeAuswahl signalQSem : : QSem IO ( ) signalQSem (QSem sem ) = do

( a v a i l , b l o c k e d ) takeMVar sem c a s e b l o c k e d o f

[] putMVar sem ( a v a i l +1, [] ) b l o c k : blocked ’ do

putMVar sem (0 , blocked ’ ) putMVar b l o c k ( )

21

Zusammenfassung

IConcurrent Haskellbietet

I Threadsauf Quellsprachenebene

I Synchronisierung mitMVars

I Durchschlankes Designeinfache Implementierung IFunktionales Paradigma erlaubtAbstraktionen

I Beispiel:Semaphoren

IN¨achste Woche:Kan¨aleundAusnahmen.

22

Referenzen

ÄHNLICHE DOKUMENTE

I Aber: Haskell Standard-IO blockiert nur den aufrufenden Thread.. IORef a). I Entweder leer oder gefüllt mit Wert vom

I Jeder Thread hat einen Identifier: abstrakter Typ ThreadId I Neuen Thread erzeugen: forkIO :: IO()→ IO ThreadId I Thread stoppen: killThread :: ThreadId → IO () I

I Aber: Haskell Standard-IO blockiert nur den aufrufenden Thread.. IORef a). I Entweder leer oder gef¨ullt mit Wert vom

• boolean tryAcquire(int permits, long timeout, TimeUnit unit) permits Freisignale nehmen (blockierend mit Timeout). •

- ajout de quelques gouttes d’une solution de chlorure de baryum : formation d’un précipité blanc. - ajout de quelques gouttes d’une solution de nitrate d’argent : pas

 Communication between user level thread library and kernel in case of many-to-many library and kernel in case of many to many.

In order to simply return to execution, we must make the process think that code at the address we obtained earlier (the current instruction from the thread context) was a piece

Diese meteorologisch optimierten Parametrisierungen werden anschließend in kontrollierter Weise mit einer Inversrechnung derart verändert, daß die resultierenden