2012-11-18 23 views
18

Próbowałem następujące podejście:Jak napisać handler Ctrl-C w Haskell?

import System.Exit 
import System.Posix.Signals 
import Control.Concurrent (threadDelay) 

main :: IO() 
main = do 
    installHandler keyboardSignal (Catch (do exitSuccess)) Nothing 
    threadDelay (1000000000) 

Ale to wyłącznie wyjście:

^CTest.hs: ExitSuccess 

na Ctrl-C, zamiast zamykania. Jak powinienem to zrobić właściwie?

Odpowiedz

20

Od docs installHandler:

handler jest zainstalowany które wywoła działanie w nowym wątku, kiedy (lub krótko po nim) jest odbierany sygnał.

i exitWith:

Uwaga: w GHC, exitWith powinna być wywoływana z głównego wątku programu, aby zakończyć proces. Po wywołaniu z innego wątku exitWith wyrzuci wyjątek ExitException jako normalny, ale wyjątek nie spowoduje zakończenia procesu.

Tak więc obsługa exitSuccess nie kończy procesu, a to jest oczekiwane (choć nieoczekiwane;) zachowanie.

Jeśli chcesz natychmiastowego działania,

import System.Exit 
import System.Posix.Signals 
import Control.Concurrent 

main :: IO() 
main = do 
    tid <- myThreadId 
    installHandler keyboardSignal (Catch (killThread tid)) Nothing 
    threadDelay (1000000000) 

zabija wątek natychmiast po odebraniu sygnału.

Mniej drastyczne, jeśli chcesz udane wyjście byłoby

import System.Exit 
import System.Posix.Signals 
import Control.Concurrent 
import qualified Control.Exception as E 

main :: IO() 
main = do 
    tid <- myThreadId 
    installHandler keyboardSignal (Catch (E.throwTo tid ExitSuccess)) Nothing 
    threadDelay (10000000) 

myślę, że będzie również działać niezawodnie, ale nie jestem do końca pewien.

+0

Co robi wiersz 'threadDelay (10000000)'? – Langston

+1

['threadDelay'] (http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Concurrent.html#v:threadDelay)" Zawiesza bieżący wątek dla danej liczby mikrosekund ", podobne do 'usleep' w C. Tutaj zawieszamy wykonywanie wyłącznie w celu zapewnienia użytkownikowi wystarczającego czasu na naciśnięcie Ctrl-C. –