Das folgende Programm erstellt zwei gleichzeitig ausgeführte Threads, die jeweils für eine zufällige Zeitspanne schlafen, bevor eine Textzeile auf stdout gedruckt wird.
%Vor%Die Ausgabe sieht im Allgemeinen ungefähr wie
aus %Vor% Wie stellen Sie sicher, dass immer nur ein Thread in stdout schreiben kann? Dies scheint der Fall zu sein, in dem STM gut sein sollte, aber alle STM-Transaktionen müssen den Typ STM a
für einige a
haben, und eine Aktion, die auf den Bildschirm druckt, hat den Typ IO a
scheint eine Möglichkeit zu sein, IO
in STM
einzubetten.
Das Sperren in der beschriebenen Weise ist mit STM
nicht möglich. Dies liegt daran, dass STM
auf optimistischem Sperren basiert und daher jede Transaktion jederzeit neu gestartet werden kann. Wenn Sie eine Operation IO
in STM
eingebettet haben, könnte sie mehrmals ausgeführt werden.
Die einfachste Lösung für dieses Problem ist die Verwendung von MVar
als Sperre:
In dieser Lösung wird die Sperre als Argument an printer
übergeben.
Manche Leute bevorzugen es, die Sperre als globale Variable der obersten Ebene zu deklarieren, aber das erfordert derzeit unsafePerformIO
und beruht auf Eigenschaften von GHC, dass AFAIK nicht Teil des Haskell-Sprachberichts ist (insbesondere beruht es auf der Tatsache, dass eine globale Variable mit nicht-polymorphem Typ höchstens einmal während der Ausführung eines Programms ausgewertet wird).
Ein bisschen Forschung, basierend auf Petr Pudláks Antwort zeigt, dass es ein Modul Control.Concurrent.Lock im concurrent-extra Paket, das eine Abstraktion um MVar ()
-basierte Sperren bietet.
Die Lösung, die diese Bibliothek verwendet, ist
%Vor%Tags und Links haskell multithreading stm