summaryrefslogtreecommitdiff
path: root/ws2015
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2015-12-23 20:46:07 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2015-12-23 20:46:07 +0100
commit3bc43b689c1177ddeca6ea012aa74728f2b121c7 (patch)
treeb811150e0f40e9b66e32f764c827b5a4b8874f07 /ws2015
parent1d27f7b9aac4058f28aa8e56cb112ad1018614d7 (diff)
downloaduni-3bc43b689c1177ddeca6ea012aa74728f2b121c7.tar
uni-3bc43b689c1177ddeca6ea012aa74728f2b121c7.tar.gz
uni-3bc43b689c1177ddeca6ea012aa74728f2b121c7.tar.bz2
uni-3bc43b689c1177ddeca6ea012aa74728f2b121c7.tar.xz
uni-3bc43b689c1177ddeca6ea012aa74728f2b121c7.zip
FFP 10
Diffstat (limited to 'ws2015')
-rwxr-xr-xws2015/ffp/blaetter/10/FFP_U10_STM.hs491
1 files changed, 491 insertions, 0 deletions
diff --git a/ws2015/ffp/blaetter/10/FFP_U10_STM.hs b/ws2015/ffp/blaetter/10/FFP_U10_STM.hs
new file mode 100755
index 0000000..9a99e86
--- /dev/null
+++ b/ws2015/ffp/blaetter/10/FFP_U10_STM.hs
@@ -0,0 +1,491 @@
1{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3
4-- Fortgeschrittene Funktionale Programmierung,
5-- LMU, TCS, Wintersemester 2015/16
6-- Steffen Jost, Alexander Isenko
7--
8-- Übungsblatt 10. 23.12.2015
9--
10-- Thema: Software Transactional Memory
11--
12-- Hinweis:
13-- Heute gibt es nur eine größere Aufgabe!
14-- Wer damit fertig ist, sollte im Anschluß zuvor
15-- übersprunge Aufgaben behandeln.
16--
17-- Für diese Übung reicht auch ein Rechner mit einem Kern.
18--
19
20
21-- A10-1 The Santa Claus problem
22--
23-- Heute wollen wir uns von Haskell ganz nebenläufig
24-- in eine weihnachtliche Stimmung versetzen lassen:
25--
26-- Der Weihnachtsmann schläft friedlich am Nordpol.
27-- Er läßt sich jedoch nur in zwei Situationen wecken:
28-- 1) Alle seine 9 Rentiere sind bereits aus dem Karibik-Urlaub
29-- zurückgekommen. Dann ist es bereits höchste Zeit,
30-- diese an den Schlitten zu binden und die Geschenke
31-- auzuliefern, denn die Rentiere möchten möglichst viel Zeit
32-- in der Karibik verbringen und kommen ungern früher als
33-- nötig zum Nordpol zurück. (Deswegen beeilen sich die
34-- Rentiere auch so beim Ausliefern aller Geschenke!)
35-- 2) Einige seiner elf Elfen haben Probleme mit
36-- Innovationsmanagement oder Fertigungstechnik
37-- für die Produktion der Geschenke und verlangen
38-- ein Executive Meeting.
39-- Da die Elfen immer irgendwelche Probleme haben,
40-- läßt sich der Weihnachtsmann nur wecken, wenn
41-- mindestens 3 Elfen nach einem Meeting verlangen;
42-- Falls nur ein oder zwei Elfen ein Gesprächsbedürfnis
43-- hegen, so müssen diese ruhig und erfurchtsvoll im
44-- Vorzimmmer abwarten.
45-- Da andererseits Meetings mit mehr als 3 Elfen
46-- absolut unproduktiv sind, müssen alle Elfen ab dem
47-- vierten ebenfalls warten, bis der Weihnachtsmann das
48-- vorherige Meeting beendet hat (waren es z.B. insgesamt
49-- 5 Elfen, dann müssen der vierte und fünfte Elf natürlich
50-- erneut auf einen sechsten Elfen warten).
51-- Der Weihnachtsmann beendet immer zuerst eine angefangene Aufgabe,
52-- bevor er eine neue Aufgabe beginnt.
53-- Treten beide Ereignisse gleichzeitig ein, so gibt er den Rentieren
54-- den Vorrang, da die Geschenke ja pünktlich ausgeliefert werden müssen.
55--
56-- Diese Problem wollen wir in Haskell mithilfe der
57-- Implementationstechnik "Software Transactional Memory"
58-- modellieren.
59--
60--
61-- Diese Aufgabenstellung stammt aus "A new excercise in concurrency"
62-- von John A. Trono, SIGCSE Bulletin, 26:8-10, 1994.
63--
64-- Eine elegante Lösung dieses Problems unter Verwendung von
65-- Software Transactional Memory wird detailliert behandelt von
66-- Simon Peyton Jones im Kapitel "Beautiful Concurrency"
67-- aus dem Buch "Beautiful Code" von Greg Wilson und Andy Oram, O'Reilly, 2007.
68--
69--
70-- Das Gerüst in dieser Datei macht bereits einige Vorschläge,
71-- doch Sie dürfen ALLES ABÄNDERN, z.B. zusätzliche Funktionsargumente
72-- zum Übergeben von TVars werden vermutlich notwendig sein, etc.
73--
74-- Versuchen Sie zuerst einmal, Santa & die Rentiere
75-- zu synchronisieren und deaktivieren Sie die Elfen.
76--
77-- Die zentrale Frage lautet:
78-- Wie viele TVars welcher Art werden gebraucht?
79--
80-- Am Ende dieser Datei befinden sich weitere Hinweise.
81-- Schauen Sie dort nach, falls Sie nicht weiter wissen.
82--
83
84
85
86module Main where
87
88
89import Data.List
90import Control.Concurrent.STM
91import Control.Concurrent
92import Control.Monad
93import System.Random
94import System.IO
95
96import Control.DeepSeq
97import qualified Data.Set as Set
98import Data.Set (Set)
99
100
101newtype ElfId = Elf Integer
102 deriving (Num, Enum, Show, Eq, Ord, NFData)
103newtype RaindeerId = Raindeer Integer
104 deriving (Num, Enum, Show, Eq, Ord, NFData)
105
106data GroupState id = GroupState
107 { waiting :: TVar [id]
108 , working :: TVar (Set id)
109 }
110
111data State = State
112 { elfs :: GroupState ElfId
113 , raindeers :: GroupState RaindeerId
114 , outChan :: Chan String
115 }
116
117initState :: IO State
118initState = State
119 <$> initGroupState
120 <*> initGroupState
121 <*> newChan
122
123initGroupState :: IO (GroupState a)
124initGroupState = GroupState
125 <$> newTVarIO []
126 <*> newTVarIO Set.empty
127
128
129main :: IO ()
130main = initState >>= main'
131
132main' :: State -> IO ()
133main' state@(State{..}) = do
134 mapM_ (forkIO . elf state) [1..11]
135 mapM_ (forkIO . rentier state) [1..9]
136 forkIO $ santa state
137
138 hSetBuffering stdin NoBuffering
139 forkIO $ forever $ readChan outChan >>= putStrLn
140
141 mloop
142 where
143 mloop = getChar >>= flip unless mloop . (== 'q')
144
145
146
147santa :: State -> IO ()
148santa State{..} = forever . join . atomically $ deliver `orElse` meeting
149 where
150 deliver = do
151 check . (>= 9) . length =<< readTVar (waiting raindeers)
152 mapM_ (flip setWorking raindeers) =<< readTVar (waiting raindeers)
153 return $ do
154 writeChan outChan "Ho! Ho! Ho! Hüja Rentiere!"
155 atomically $ check . Set.null =<< readTVar (working raindeers)
156 meeting = do
157 check . (>= 3) . length =<< readTVar (waiting elfs)
158 mapM_ (flip setWorking elfs) =<< take 3 <$> readTVar (waiting elfs)
159 return $ do
160 writeChan outChan "Ho! Ho! Ho! Besprechung eröffnet!"
161 atomically $ check . Set.null =<< readTVar (working elfs)
162
163
164
165elf :: State -> ElfId -> IO ()
166elf State{..} eid = forever $ do
167 writeChan outChan $ show eid ++ " arbeitet."
168 randomDelay 6
169 writeChan outChan $ show eid ++ " ist traurig."
170
171 atomically $ setWaiting eid elfs
172 atomically $ check =<< isWorking eid elfs
173
174 writeChan outChan $ show eid ++ " hat Besprechung."
175 randomDelay 1
176 writeChan outChan $ show eid ++ " hat Besprechung verlassen."
177 atomically $ unregister eid elfs
178
179
180
181rentier :: State -> RaindeerId -> IO ()
182rentier State{..} rid = forever $ do
183 writeChan outChan $ show rid ++ " ist im Urlaub."
184 randomDelay 8
185 writeChan outChan $ show rid ++ " ist zurück."
186
187 atomically $ setWaiting rid raindeers
188 atomically $ check =<< isWorking rid raindeers
189
190 writeChan outChan $ show rid ++ " liefert Geschenke."
191 randomDelay 2
192 writeChan outChan $ show rid ++ " ist fertig mit ausliefern."
193 atomically $ unregister rid raindeers
194
195
196
197--------------------
198-- Hilfsfunktionen
199--------------------
200
201randomDelay :: Int -> IO ()
202-- Delay for a random time between 1 and n * 500,000 microseconds
203randomDelay n = do
204 let t = n * 500000
205 waitTime <- getStdRandom (randomR (1, t))
206 threadDelay waitTime
207
208snoc :: a -> [a] -> [a]
209snoc = flip (++) . pure
210
211setWaiting :: (Ord id, NFData id) => id -> GroupState id -> STM ()
212setWaiting id st@(GroupState{..}) = unregister id st >> modifyTVar' waiting (snoc id $!!)
213
214setWorking :: (Ord id, NFData id) => id -> GroupState id -> STM ()
215setWorking id st@(GroupState{..}) = unregister id st >> modifyTVar' working (Set.insert id $!!)
216
217isWorking :: (Ord id, NFData id) => id -> GroupState id -> STM Bool
218isWorking id GroupState{..} = Set.member id <$> readTVar working
219
220unregister :: (Ord id, NFData id) => id -> GroupState id -> STM ()
221unregister id GroupState{..} = do
222 modifyTVar' waiting (filter (/= id) $!!)
223 modifyTVar' working (Set.delete id $!!)
224
225{- Eventuell nützliche Funktion aus Modul Control.Monad.STM:
226
227check :: Bool -> STM ()
228check b = if b then return () else retry
229
230-}
231
232
233
234
235
236----------------------------------------------------------------
237-- WEITERE HINWEISE:
238----------------------------------------------------------------
239
240
241
242{-
243 * Beide Quellen zur Aufgabe finden sich problemlos im Internet,
244 unter anderem auch im Haskell Center auf fpcomplete.com.
245 Die elegante Lösung von Simon Peyton Jones ist auf einem sehr hohen
246 Abstraktionsniveau, welches wir vermutlich nicht auf Anhieb in der
247 Übung erreichen können.
248
249 Natürlich ist es schön und vermeidet Fehler, wenn man zum Beispiel
250 den ähnlichen Code für Rentiere und Elfe mit einer generischen
251 Funktion abhandeln kann, aber für den Anfang is es okay, spezielleren
252 Code zu schreiben, so lange dieser korrekt ist.
253 Gemeinsamkeiten im Code kann man hinterher immer noch Erkennen
254 und generalisieren.
255
256 Unser Lösungsvorschlag im UniworX wird daher auch eine weniger elegante
257 Version zeigen. Es wird jedoch ausdrücklich empfohlen, hinterher
258 einmal auch die kürzere Lösung von Simon Peyton Jones durchzudenken.
259-}
260
261
262
263{-
264 * Die Grundidee ist wie folgt:
265
266 Jedes Rentier/Elf durchläuft folgende Endlosschleife:
267 1. Eigene Arbeit erledigen (durch Aufruf an "randomDelay" symbolisiert)
268 2. Bereitschaft an Weihnachtsmann Prozess signalisieren
269 3. Warten, bis Weihnachtsmann Startzeichen gibt.
270 4. Arbeit mit Weihnachtsmann erledigen (durch Aufruf an "randomDelay" symbolisiert)
271 5. Weihnachtsmann das Ende der eigenen Arbeit signalisieren
272
273 Der Weihnachtsmann (bzw. dessen PA, da der Weihnachtsmann
274 selbst ja eigentlich schläft), prüft ständig ob genug
275 Rentiere oder Elfen seine Aufmerksamkeit verlangen, und
276 gibt ggf. den entsprechenden Rentieren/Elfen das Startsignal.
277 Danach wartet er darauf, dass diese noch das Ende der jeweiligen Aufgabe signalisieren.
278-}
279
280
281
282{-
283 Signalisieren soll ausschließlich über TVars erfolgen,
284 warten kann mit retry oder check (siehe Hilfsfunktionen) realisiert werden.
285-}
286
287
288
289{-
290 Die Antowrt auf die Frage, wie viele TVars welcher Art gebraucht werden,
291 kann ganz unterschiedlich beantwortet werden.
292
293 Zum Beispiel verwendet unser Lösungsvorschlag mehrere globale TVars,
294 während die Lösung von Simon Peyton Jones nur 2 in einem
295 speziellen Datentyp verpackte TVars verwendet, welche auf weitere,
296 je nach Aufgabe dynamisch angelegte, TVars verweisen.
297-}
298
299
300
301{-
302
303Beispielausgabe mit vielen Extra-Ausgaben an der Konsole zum Verständnis des Ablaufs:
304
305
306Elf 21 ist traurig. Wartezimmer vorher: 0
307Elf 16 ist traurig. Wartezimmer vorher: 1
308Elf 11 ist traurig. Wartezimmer vorher: 2
309Ho! Ho! Ho! Besprechung eröffnet [21,16,11] !
310Elf 21 hat Besprechung.
311Elf 16 hat Besprechung.
312Elf 11 hat Besprechung.
313Rentier 8 ist zurück. Vorher im Stall: 0
314Elf 20 ist traurig. Wartezimmer vorher: 0
315Elf 13 ist traurig. Wartezimmer vorher: 1
316Rentier 7 ist zurück. Vorher im Stall: 1
317Ho! Ho! Ho! Besprechung vorbei!
318Rentier 6 ist zurück. Vorher im Stall: 2
319Elf 14 ist traurig. Wartezimmer vorher: 2
320Elf 11 ist traurig. Wartezimmer vorher: 3
321Elf 17 ist traurig. Wartezimmer vorher: 4
322Elf 15 ist traurig. Wartezimmer vorher: 5
323Ho! Ho! Ho! Besprechung eröffnet [20,13,14] !
324Elf 20 hat Besprechung.
325Elf 13 hat Besprechung.
326Elf 14 hat Besprechung.
327Rentier 2 ist zurück. Vorher im Stall: 3
328Ho! Ho! Ho! Besprechung vorbei!
329Ho! Ho! Ho! Besprechung eröffnet [11,17,15] !
330Elf 11 hat Besprechung.
331Elf 17 hat Besprechung.
332Elf 15 hat Besprechung.
333Elf 14 ist traurig. Wartezimmer vorher: 0
334Elf 13 ist traurig. Wartezimmer vorher: 1
335Elf 17 ist traurig. Wartezimmer vorher: 2
336Elf 19 ist traurig. Wartezimmer vorher: 3
337Elf 16 ist traurig. Wartezimmer vorher: 4
338Ho! Ho! Ho! Besprechung vorbei!
339Ho! Ho! Ho! Besprechung eröffnet [14,13,17] !
340Elf 14 hat Besprechung.
341Elf 13 hat Besprechung.
342Elf 17 hat Besprechung.
343Elf 18 ist traurig. Wartezimmer vorher: 2
344Elf 21 ist traurig. Wartezimmer vorher: 3
345Elf 12 ist traurig. Wartezimmer vorher: 4
346Ho! Ho! Ho! Besprechung vorbei!
347Ho! Ho! Ho! Besprechung eröffnet [19,16,18] !
348Elf 19 hat Besprechung.
349Elf 16 hat Besprechung.
350Elf 18 hat Besprechung.
351Rentier 9 ist zurück. Vorher im Stall: 4
352Rentier 3 ist zurück. Vorher im Stall: 5
353Elf 20 ist traurig. Wartezimmer vorher: 2
354Ho! Ho! Ho! Besprechung vorbei!
355Ho! Ho! Ho! Besprechung eröffnet [21,12,20] !
356Elf 21 hat Besprechung.
357Elf 12 hat Besprechung.
358Elf 20 hat Besprechung.
359Rentier 5 ist zurück. Vorher im Stall: 6
360Elf 15 ist traurig. Wartezimmer vorher: 0
361Rentier 4 ist zurück. Vorher im Stall: 7
362Ho! Ho! Ho! Besprechung vorbei!
363Rentier 1 ist zurück. Vorher im Stall: 8
364Elf 12 ist traurig. Wartezimmer vorher: 1
365Elf 20 ist traurig. Wartezimmer vorher: 2
366Ho! Ho! Ho! Hüja Rentiere [1,4,5,3,9,2,6,7,8] !
367Rentier 8 liefert Geschenke.
368Rentier 7 liefert Geschenke.
369Rentier 6 liefert Geschenke.
370Rentier 2 liefert Geschenke.
371Rentier 9 liefert Geschenke.
372Rentier 3 liefert Geschenke.
373Rentier 5 liefert Geschenke.
374Rentier 4 liefert Geschenke.
375Rentier 1 liefert Geschenke.
376Elf 17 ist traurig. Wartezimmer vorher: 3
377Elf 21 ist traurig. Wartezimmer vorher: 4
378Elf 11 ist traurig. Wartezimmer vorher: 5
379Elf 13 ist traurig. Wartezimmer vorher: 6
380Ho! Ho! Ho! Was für ein Fest!
381Ho! Ho! Ho! Besprechung eröffnet [15,12,20] !
382Elf 15 hat Besprechung.
383Elf 12 hat Besprechung.
384Elf 20 hat Besprechung.
385Rentier 6 ist zurück. Vorher im Stall: 0
386Ho! Ho! Ho! Besprechung vorbei!
387Ho! Ho! Ho! Besprechung eröffnet [17,21,11] !
388Elf 17 hat Besprechung.
389Elf 21 hat Besprechung.
390Elf 11 hat Besprechung.
391Elf 14 ist traurig. Wartezimmer vorher: 1
392Ho! Ho! Ho! Besprechung vorbei!
393Elf 19 ist traurig. Wartezimmer vorher: 2
394Elf 16 ist traurig. Wartezimmer vorher: 3
395Rentier 9 ist zurück. Vorher im Stall: 1
396Elf 18 ist traurig. Wartezimmer vorher: 4
397Ho! Ho! Ho! Besprechung eröffnet [13,14,19] !
398Elf 13 hat Besprechung.
399Elf 14 hat Besprechung.
400Elf 19 hat Besprechung.
401Elf 17 ist traurig. Wartezimmer vorher: 2
402Elf 12 ist traurig. Wartezimmer vorher: 3
403Rentier 3 ist zurück. Vorher im Stall: 2
404Ho! Ho! Ho! Besprechung vorbei!
405Ho! Ho! Ho! Besprechung eröffnet [16,18,17] !
406Elf 16 hat Besprechung.
407Elf 18 hat Besprechung.
408Elf 17 hat Besprechung.
409Elf 11 ist traurig. Wartezimmer vorher: 1
410Rentier 5 ist zurück. Vorher im Stall: 3
411Elf 14 ist traurig. Wartezimmer vorher: 2
412Elf 18 ist traurig. Wartezimmer vorher: 3
413Rentier 1 ist zurück. Vorher im Stall: 4
414Ho! Ho! Ho! Besprechung vorbei!
415Ho! Ho! Ho! Besprechung eröffnet [12,11,14] !
416Elf 12 hat Besprechung.
417Elf 11 hat Besprechung.
418Elf 14 hat Besprechung.
419Elf 15 ist traurig. Wartezimmer vorher: 1
420Elf 19 ist traurig. Wartezimmer vorher: 2
421Ho! Ho! Ho! Besprechung vorbei!
422Ho! Ho! Ho! Besprechung eröffnet [18,15,19] !
423Elf 18 hat Besprechung.
424Elf 15 hat Besprechung.
425Elf 19 hat Besprechung.
426Elf 21 ist traurig. Wartezimmer vorher: 0
427Rentier 8 ist zurück. Vorher im Stall: 5
428Rentier 2 ist zurück. Vorher im Stall: 6
429Elf 17 ist traurig. Wartezimmer vorher: 1
430Rentier 7 ist zurück. Vorher im Stall: 7
431Elf 13 ist traurig. Wartezimmer vorher: 2
432Elf 20 ist traurig. Wartezimmer vorher: 3
433Ho! Ho! Ho! Besprechung vorbei!
434Ho! Ho! Ho! Besprechung eröffnet [21,17,13] !
435Elf 21 hat Besprechung.
436Elf 17 hat Besprechung.
437Elf 13 hat Besprechung.
438Rentier 4 ist zurück. Vorher im Stall: 8
439Elf 16 ist traurig. Wartezimmer vorher: 1
440Elf 12 ist traurig. Wartezimmer vorher: 2
441Elf 19 ist traurig. Wartezimmer vorher: 3
442Ho! Ho! Ho! Besprechung vorbei!
443Ho! Ho! Ho! Hüja Rentiere [4,7,2,8,1,5,3,9,6] !
444Rentier 6 liefert Geschenke.
445Rentier 9 liefert Geschenke.
446Rentier 3 liefert Geschenke.
447Rentier 5 liefert Geschenke.
448Rentier 1 liefert Geschenke.
449Rentier 8 liefert Geschenke.
450Rentier 2 liefert Geschenke.
451Rentier 7 liefert Geschenke.
452Rentier 4 liefert Geschenke.
453Elf 17 ist traurig. Wartezimmer vorher: 4
454Elf 13 ist traurig. Wartezimmer vorher: 5
455Ho! Ho! Ho! Was für ein Fest!
456Ho! Ho! Ho! Besprechung eröffnet [20,16,12] !
457Elf 20 hat Besprechung.
458Elf 16 hat Besprechung.
459Elf 12 hat Besprechung.
460Rentier 3 ist zurück. Vorher im Stall: 0
461Ho! Ho! Ho! Besprechung vorbei!
462Ho! Ho! Ho! Besprechung eröffnet [19,17,13] !
463Elf 19 hat Besprechung.
464Elf 17 hat Besprechung.
465Elf 13 hat Besprechung.
466Rentier 5 ist zurück. Vorher im Stall: 1
467Elf 11 ist traurig. Wartezimmer vorher: 0
468Elf 16 ist traurig. Wartezimmer vorher: 1
469Rentier 4 ist zurück. Vorher im Stall: 2
470Elf 15 ist traurig. Wartezimmer vorher: 2
471Elf 14 ist traurig. Wartezimmer vorher: 3
472Elf 18 ist traurig. Wartezimmer vorher: 4
473Rentier 6 ist zurück. Vorher im Stall: 3
474Ho! Ho! Ho! Besprechung vorbei!
475Ho! Ho! Ho! Besprechung eröffnet [11,16,15] !
476Elf 11 hat Besprechung.
477Elf 16 hat Besprechung.
478Elf 15 hat Besprechung.
479Elf 21 ist traurig. Wartezimmer vorher: 2
480Elf 12 ist traurig. Wartezimmer vorher: 3
481Ho! Ho! Ho! Besprechung vorbei!
482Ho! Ho! Ho! Besprechung eröffnet [14,18,21] !
483Elf 14 hat Besprechung.
484Elf 18 hat Besprechung.
485Elf 21 hat Besprechung.
486Elf 14 ist traurig. Wartezimmer vorher: 1
487Rentier 2 ist zurück. Vorher im Stall: 4
488Ho! Ho! Ho! Besprechung vorbei!
489q
490
491-}