Могу ли я отключить контроль-C? - PullRequest
12 голосов
/ 23 января 2012

Есть ли способ (временно) отключить эффект прерывания control-C в обычном исполняемом файле Haskell, работающем в оболочке?

Контекст: у меня есть небольшое упражнение, которое я задаю каждый год,Это игра, в которой учащиеся бегают по выражениям, вызывая сопоставление с образцом, когда это необходимо, и переписываются в окне оболочки с помощью hncurses.Когда студенты закончили последнюю головоломку, они получают индивидуальный пароль, который им нужно отправить мне.Будучи ветеранами Windows и новичками в Unix, и, конечно, (виртуозно) ленивыми, они, как правило, выбирают пароль и набирают control-C.Это приводит к непреднамеренному прерыванию работы программы и исчезновению пароля.Единственный способ восстановить это - повторить упражнение.Как жестоко!

Хотя есть и другие способы решения этой проблемы (например, печать предупреждающего сообщения или запись пароля в файл), мне интересно знать, есть ли способ отключить control-C.

Ответы [ 3 ]

12 голосов
/ 23 января 2012

Да, вы просто должны временно игнорировать SIGINT:

import Prelude hiding (catch)
import Control.Exception
import Control.Concurrent
import System.Posix.Signals

-- Ensures the original handler is restored even after an exception.
--
-- installHandler returns the previous signal handler, so if you're
-- tied to some existing main loop, you could instead just keep
-- its return value around for later restoration.
ignoreSignal :: Signal -> IO a -> IO a
ignoreSignal sig = bracket (install Ignore) install . const
  where install handler = installHandler sig handler Nothing

pause :: IO ()
pause = threadDelay 2000000

main :: IO ()
main = do
  ignoreSignal keyboardSignal $ do
    putStrLn "Ctrl+C disabled."
    pause
  putStrLn "\nCtrl+C re-enabled."
  pause

(Вы также можете написать keyboardSignal как sigINT, если хотите назвать его более прямо.)

Вы также можете заменить Ignore на Catch m, где m - это какое-либо действие, которое печатает руководство по правильному способу копирования текста. (Однако будьте осторожны; он будет выполняться в отдельном потоке на Haskell.)

8 голосов
/ 23 января 2012

Быстро и просто, используйте оболочку:

stty intr ^T
run your haskell program here
stty intr ^C

Это дает дополнительное преимущество, заключающееся в том, что программы все еще могут прерываться.

1 голос
/ 23 января 2012

Вы могли бы явно перехватить исключение, которое, я считаю, UserInterrupt:

handle (\exception -> do
     case fromException exception of
          Just UserInterrupt -> -- return to problem
          _                  -> error "unhandled exception") playWithStudents
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...