• Keine Ergebnisse gefunden

Nebenl¨ aufigkeit in Haskell: Abstraktionen und Ausnahmen

N/A
N/A
Protected

Academic year: 2022

Aktie "Nebenl¨ aufigkeit in Haskell: Abstraktionen und Ausnahmen"

Copied!
5
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 08.12.09:

Nebenl¨ aufigkeit in Haskell: Abstraktionen und Ausnahmen

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

Tagesmen¨ u

IAbstraktionen:Kan¨ale IFallbeispiel:

ITalk

IAusnahmebehandlung:

IErweiterbare Ausnahmen

IUnscharfe Ausnahmen

IAsynchrone Ausnahmen

3

Kan¨ ale

ITypsicheres Lesen/Schreiben inFIFO-Ordnung

IBlockiertwenn leer data Chan a . . .

newChan : : IO ( Chan a )

writeChan : : Chan a a IO ( ) readChan : : Chan a IO a

I Bonus:Duplizierbar (“Broadcast”)

4

Kan¨ ale

IEin Kanal besteht aus Strom mit einem Lese- und Schreibende:

data Chan a = Chan (MVar ( Stream a ) ) (MVar ( Stream a ) )

IHierMVar, um Lesen/Schreiben zu synchronisieren IEin Strom istMVar (ChItem a):

Ientweder leer,

Ioder enth¨alt Werte aus Kopfaund Rest.

type Stream a = MVar ( ChItem a ) data ChItem a = ChItem a ( Stream a )

5

In einen Kanal schreiben

INeues Ende (hole) anlegen IWert in altes Ende schreiben

IZeiger auf neues Ende setzen

writeChan : : Chan a a IO ( ) writeChan ( Chan w r i t e ) v a l = do

new hole newEmptyMVar o l d h o l e takeMVar w r i t e

putMVar o l d h o l e ( ChItem v a l new hole ) putMVar w r i t e new hole

IKann nicht blockieren —writeimmer gef¨ullt.

IOriginal-Code benutztmodifyMVar— Ausnahmesicher!

6

Aus Kanal lesen

IAnfang auslesen, Anfangszeiger weitersetzen IKann blockieren(*)wenn Kanal leer

readChan : : Chan a IO a readChan ( Chan read ) = do

r e a d e n d takeMVar read

( ChItem v a l new read end ) readMVar r e a d e n d −−* putMVar read new read end

r e t u r n v a l

IreadMVar :: MVar a→IO aliestMVar, schreibt Wert zur¨uck.

IreadMVarstatttakeMVar, um Duplikation zu erm¨oglichen

Neuen Kanal erzeugen

ILese-Ende = Schreib-Ende newChan : : IO ( Chan a ) newChan = do

h o l e newEmptyMVar read newMVar h o l e w r i t e newMVar h o l e r e t u r n ( Chan read w r i t e )

(2)

Weitere Kanalfunktionen

IZeichen wieder vorne einh¨angen:

unGetChan : : Chan a a IO ( )

IKanal duplizieren (Broadcast):

dupChan : : Chan a IO ( Chan a )

IKanalinhalt als (unendliche) Liste:

getChanContents : : Chan a IO [ a ]

IAuswertung terminiert nicht, sondern blockiert

9

Fallbeispiel: Talk

IZiel: ein Programm, um sich ¨uber das Internetz zu unterhalten (talk, IRC, etc.)

IVerteilte Architektur:

Client Client Client

Client Server

IHier: Implementierung des Servers

I Netzverbindungen durchSocket

10

Socketprogrammierung

ISocket erzeugen, an Namen binden, mitlisten Verbindungsbereitschaft anzeigen

IZustandsbasierte Verbindung:

IServerseite: mitacceptauf eingehende Verbindungen warten

IJede Verbindung erzeugt neuen Filedescriptor

inh¨arent nebenl¨aufiges Problem!

IClientseite: MitconnectVerbindung aufnehmen.

IZustandslose Verbindung:sendTozum Senden,recvFromzum Empfangen.

IGHC-ModulNetwork

ILow-level Funktionen inNetwork.Socket

11

Das Modul Network

ISockets:

type Socket

data PortID = S e r v i c e S t r i n g −−z.B. ”ftp”

| PortNumber PortNumber

| UnixSocket S t r i n g −−Socket mit Namen type Hostname = S t r i n g

i n s t a n c e Num PortNumber IZustandsbasiert:

l i s t e n O n : : PortID IO Socket

accept : : Socket IO ( Handle , Hostname , PortNumber ) connectTo : : Hostname PortID IO Handle

IZustandslos:

sendTo : : HostName PortID S t r i n g IO ( ) recvFrom : : HostName PortID IO S t r i n g

12

Serverarchitektur

IEin Kanal zur Nachrichtenverbreitung:

Ieine Nachricht, viele Empf¨anger (broadcast)

IRealisierung mittelsdupChan IZentraler Scheduler

IF¨ur jede ankommende Verbindung neuer Thread:

INachrichten vom Socket auf den Kanal schreiben

INachrichten vom Kanal in den Socket schreiben

IProblem: Wie aus SocketoderKanal lesen wenn beide blockieren?

IL¨osung: Zwei Threads IClient:telnet

13

Talk 0.1: Hauptprogramm

main =do a : getArgs

l e t p = f r o m I n t e g e r ( read a ) s l i s t e n O n ( PortNumber p ) chnewChan

loop s ch

14

Talk 0.1: Hauptschleife

loop s ch = f o r e v e r $ do ( handle , wh , p ) accept s h S e t B u f f e r i n g handle No B uffering

putStrLn $ ”New c o n n e c t i o n from ”++ wh++

” on p o r t ”++ show p

ch2 dupChan ch

f o r k I O ( newUser handle ch2 )

15

Talk 0.1: Benutzerprozess

newUser : : Handle Chan S t r i n g IO ( ) newUser s o c k e t msgch =

f o r k I O ( f o r e v e r read ) f o r e v e r w r i t e where read : : IO ( )

read = hGetLine s o c k e t =writeChan msgch w r i t e : : IO ( )

w r i t e = readChan msgch=hPutStrLn s o c k e t

16

(3)

Talk 0.1: Zusammenfassung

Nachteile:

INachrichten stauen sich im Kanal

IKeine Fehlerbehandlung

IBenutzer anonym

17

Ausnahmebehandlung in Haskell98

IHaskell 98: Fehler leben im IO-Monaden.

IFehler fangen:

catch : : IO a ( I O E r r o r IO a ) IO a

I Variante:try :: IO aIO (Either IOError a) IFehler erzeugen:

u s e r E r r o r : : S t r i n g I O E r r o r i o E r r o r : : I O E r r o r IO a

IOder durch andere Operationen im IO-Monaden.

18

Fehler analysieren

IFunktionen, die im Handler benutzt werden k¨onnen:

i s A l r e a d y E x i s t s E r r o r : : I O E r r o r Bool i s D o e s N o t E x i s t E r r o r : : I O E r r o r Bool i s A l r e a d y I n U s e E r r o r : : I O E r r o r Bool i s F u l l E r r o r : : I O E r r o r Bool isEOFError : : I O E r r o r Bool i s I l l e g a l O p e r a t i o n : : I O E r r o r Bool i s P e r m i s s i o n E r r o r : : I O E r r o r Bool i s U s e r E r r o r : : I O E r r o r Bool i o e G e t E r r o r S t r i n g : : I O E r r o r S t r i n g ioeGetHandle : : I O E r r o r Maybe Handle ioeGetFileName : : I O E r r o r Maybe F i l e P a t h

19

Talk 0.2: Hauptschleife

loop s ch = f o r e v e r $ do ( handle , wh , p ) a c ce p t s h S e t B u f f e r i n g handle No B uf f er in g i n s t a l l H a n d l e r sigPIPE I g n o r e Nothing putStrLn $ ”New c o n n e c t i o n from ”++ wh++

” on p o r t ”++ show p ch2dupChan ch

f o r k I O ( catch ( newUser handle wh ch2 ) (λ hClose handle ) ) IFehlerbehandlung f¨urnewUser(kein guter Stil) ISIGPIPEignorieren

20

Talk 0.2: Benutzerprozess

Teil 1: Anmeldeprozedur newUser s wh msgch = do

hPutStrLn s ” H e l l o t h e r e . P l e a s e send your nickname . ” n i c k do nmhGetLine s

r e t u r n ( f i l t e r ( not . i s C o n t r o l ) nm) hPutStrLn s $ ” Nice to meet you , ”++ n i c k++ ” ! ” writeChan msgch $ n i c k++ ”@”++ wh++ ” has j o i n e d . ” (Fortsetzung)

21

Talk 0.2: Benutzerprozess

Teil 2: Hauptschleife:

wp f o r k I O w r i t e

catch ( read ( ( n i c k ++ ” : ” ) ++) ) $ λe→ do k i l l T h r e a d wp

writeChan msgch $

i f isEOFError e then n i c k++ ”@”++ wh++ ” has l e f t . ” e l s e n i c k++ ”@”++ wh++ ” l e f t h a s t i l y ( ”++

i o e G e t E r r o r S t r i n g e++ ” ) ” hClose s where

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

hGetLine s=writeChan msgch . f w r i t e : : IO ( )

w r i t e = f o r e v e r $ readChan msgch=hPutStrLn s

22

Talk 0.2: Zusammenfassung

Vorteile:

IRobust

IFehlerbehandlung f¨ur Benutzerprozess

IAnmeldeprozedur: Benutzer hat Namen

ISchnell verkaufen!

Probleme mit der Ausnahmebehandlung in Haskell98

IKeineAusnahmebehandlung f¨urrein funktionalenCode.

I error :: StringabrichtProgrammausf¨uhrungab;

I z.B.Fehlerbeiread :: Read aStringa?

I readIO :: Read a⇒String→IO awirft Ausnahme

I Laufzeitfehler(pattern match, fehlendeKlassenmethoden, . . . ) IKeine Behandlung vonasynchronen Ausnahmenm¨oglich.

I Nebenl¨aufige Fehler, e.g. stack overflow, Speichermangel, Interrupts;

(4)

Probleme mit rein funktionalen Ausnahmen.

IWarum nicht einfachthrow :: Exceptiona?

IWird die Ausnahme geworfen?

l e n g t h [ throw e x c e p t i o n ]

IAbh¨angig von Tiefe der Auswertung (wertetlengthArgument aus?) IWelche Ausnahme wird geworfen:

throw ex1 + throw ex2

IAbh¨angig von Reihenfolge der Auswertung der Argumente IAber: Auswertungsreihenfolge in Haskell98unspezifiziert!

25

Unscharfe Ausnahmen.

INormaleAusnahmen:Wert eines Ausdrucks=NormalerWert oder Ausnahme

data Maybe a = J u s t a | Nothing data E i t h e r a = L e f t S t r i n g | Right a

IUnscharfeAusnahmen:Wert eines Ausdrucks=NormalerWert oder Mengevon m¨oglichenAusnahmen

I Menge wird nicht konstruiert — semantisches Konstrukt.

26

Unscharfe Ausnahmen fangen.

IAusnahmen fangen ist monadisch:

IFunktionbogus :: a(Exceptiona)ah¨atte alten Probleme IDeterminisierungtrennenvonAusnahmebehandlung:

I evaluate :: aIO awertet Ausdruck aus, wirft ggf. m¨ogliche Ausnahme.

IAusnahme durch Auswertungsreihenfolge bestimmt.

Icatch :: IO a→(Exception→IO a)→IO awie vorher.

IUnscharfeAusnahmen k¨onnen¨uberallgeworfen, aber nur im IO-Monaden gefangen werden.

27

Asynchrone Ausnahmen

IModelliert durch

throwTo : : ThreadId E x c e p t i o n IO ( )

IAusnahme wird inanderemThread geworfen.

IModelliertalle Situationenwie Interrupts etc.

28

Asynchrone Ausnahmen: Beispiel

IParallele Auswertungzweier IO-Statements:

IWerzuerstfertig istbeendetAuswertung.

parIO : : IO a IO a IO a parIO a1 a2 =

domnewEmptyVar ;

c1 f o r k I O ( a1 =putMVar m) c2 f o r k I O ( a2 =putMVar m) r takeMVar m

throwTo c1 K i l l throwTo c2 K i l l r e t u r n r

29

Asynchrone Ausnahmen: Beispiel

ITimeout-Operator:

IWenn kein Ergbnis nachnMikrosekunden,Nothing timeout : : I n t IO a IO ( Maybe a ) timeout n a = parIO ( ra ; r e t u r n ( J u s t r ) )

( t h r e a d D e l a y n ; r e t u r n Nothing )

30

Unscharfe Ausnahmen: Benutzung

IZur Benutzung:import Control.Exception(nurghc) IUmErweiterbarkeitzu gew¨ahrleisten:

ITypklasseException, alle Ausnahmen sind Instanzen

IAchtung, erst seit ghc 6.10.

IAchtung:per defaultnormaleAusnahmen (Haskell98) definiert

I ¨Uberlagerung durchImportoder Disambiguierung

IAusnahmen fangen:

catch : : E x c e p t i o n e IO a ( e IO a ) IO a t r y : : E x c e p t i o n e IO a IO ( E i t h e r e a )

31

Vorsicht bei Ausnahmen

IAusnahmen und Nebenl¨aufigkeit

IAusnahmen k¨onnen in anderen Thread geworfen werden!

chnewChan

f o r k I O ( f o r e v e r $ do readChan ch=putStrLn ) catch (do l e t x= . . .

writeChan ch x ) (λe . . . )

IAusnahme wird in reader-Thread geworfen!

I Abhilfe: Auswertung mitevaluateforcieren.

32

(5)

Ausnahmen: Achtung!

IFehlerabfrage ersetztkeineAusnahmebehandlung:

b d o e s D i r e c t o r y E x i s t name

when ( not b ) $ c r e a t e D i r e c t o r y name

IZweite Aktionkann fehlschlagen!

33

Zusammenfassung

IKan¨ale: N¨utzlicheKommunikationsabstraktion IUnscharfeAusnahmen:

I K¨onnen inbeliebigemCode auftreten

I Werden imIO-Monaden gefangen IAsynchroneAusnahmen:

I Werden inanderemThread ausgel¨ost IAusnahmebehandlung:

I Essentiellf¨ur robuste Programmierung

I NurAusnahmen fangen, die man behandelt!

I Fehlerabfrage ersetztkeineAusnahmebehandlung

34

Referenzen

ÄHNLICHE DOKUMENTE

K¨ uhlschrank ist, dann schreibe Notiz an den K¨ uhlschrank, gehe Milch kaufen, stelle die Milch in den K¨ uhlschrank und entferne danach die Notiz am K¨ uhlschrank..

Linker General schickt Boten los: “Nachricht erhalten” Linker General kann nicht sicher sein, dass der Bote ankommt. ⇒ wartet auf Best¨ atigung vom

blockiert: Prozess darf keine Schritte ausf¨ uhren Blockieren / Entblockieren durch Programmbefehle, nicht durch Scheduler..

Initial: wartend: atomares Register, am Anfang 0 kunden: genereller Semaphor, am Anfang 0 mutex: bin¨ arer Semaphor, am Anfang 1 synch,friseur: bin¨ arer Semaphor am Anfang 0

signalC(cond) kann effektlos sein: Entweder Prozess in cond wird entblockiert, oder effektlos, wenn cond leer ist. TCS | 06 Programmierprimitiven II | WS 2019/20 17/53

TCS | 07 Programmierprimitiven III | WS 2019/20 22/61 Kan¨ ale Tuple Spaces: Das Linda Modell.. n¨ utzlich bei.. n¨ utzlich bei.. n¨ utzlich bei.. n¨ utzlich bei.. n¨ utzlich bei..

2 Halten und Warten (Hold and Wait): Ein Prozess kann eine Ressource anfordern (auf eine Ressource warten), w¨ ahrend er eine andere Ressource bereits belegt hat.. 3 Keine

4 Zirkul¨ ares Warten: Es gibt zyklische Abh¨ angigkeit zwischen wartenden Prozessen: Jeder wartende Prozess m¨ ochte Zugriff auf die Ressource, die der n¨ achste Prozesse im