HaskellでCtrl-Cを制御する

2015/04/26

SIGINT等のシグナルの扱い方です。

tl;dr

System.Posix.Signalsを使います


Ctrl-Cが押されたらクロージングの処理を伴って終了するプログラムを書いてみます。

import Control.Concurrent
import System.Posix.Signals

main :: IO ()
main = do
    tid <- myThreadId
    let handler = do
            putStrLn "goodbye!"
            killThread tid
    installHandler keyboardSignal (Catch handler) Nothing

    let loop n = do
            putStr $ show n ++ ", "
            threadDelay 1000000
            loop (n+1)
    loop 0

実行してみましょう

$ runhaskell Main.hs
0, 1, 2, 3, 4, 5, ^Cgoodbye!
Main.hs: thread killed
$

ちゃんとgoodbyeと出力されて終了しました!killThreadは例外を伴って終了するのでMain.hs: thread killedというメッセージが出てしまっています。もし気になるなら例外を握りつぶすかMVarを使って終了を監視する仕組みを作るといいでしょう。

肝心のSignalを制御する関数はinstallHandler :: Signal -> Handler -> Maybe SignalSet -> IO Handlerです。Signelには制御するSignal、HandlerにはSignalが投げられた時の処理、Maybe SignalSetには処理時にブロックする他のSignalを指定します。

Signalの値は予め用意されていて

Function Signal
keyboardSignal SIGINT
keyboardStop SIGTSTP
keyboardTermination SIGQUIT
openEndedPipe SIGPIPE

と言った感じです。

HandlerDefaultにすれば標準の動作を、Ignoreにすれば何もしなくなり、Catch (IO ())で処理を記述すればSignalが投げられた時の処理を記述することができます。上の例ではhandlerという関数にメッセージの表示とメインスレッドの停止の処理を書いてHandlerとして渡していました。

簡単に解説しましたがまだまだ色々な使い方ができるので是非一度System.Posix.Signalsを読んでみてください(^^)

このエントリーをはてなブックマークに追加