2013-05-27 12 views
8

İsteğe bağlı olarak getChar eylemini iptal etmek istiyorum. Ben aşağıdaki işlevi gerekir: Bir karakter kullanılabilir duruma gelmeden abort denir sürece,HowChar güvenli bir şekilde nasıl iptal edilir?

getChar' :: (Char -> IO()) -> IO (IO()) 

abort <- getChar' callback durumunda, bir karakter standart girdi okunur. Bir karakter okunduğunda, callback ile çağrılır.

import Control.Monad 
import Control.Concurrent 

getChar' :: (Char -> IO()) -> IO (IO()) 
getChar' callback = do 
    v <- newEmptyMVar 
    tid <- forkIO $ do 
     c <- getChar 
     b <- tryPutMVar v() 
     when b $ callback c 
    return $ do 
     b <- tryPutMVar v() 
     when b $ killThread tid 

sorun killThread kömürü okuduktan sonra ancak Mvar içine () koymadan önce parçacığı iptal edebilir olmasıdır:

Aşağıdaki prototip uygulama var.

Bu sorunun nasıl çözüleceğine dair bir fikrim yok, temel pakette bu mümkün mü? Değilse, diğer paketlerde uygulanan benzer bir işlev gördünüz mü?

cevap

1

Bunu başarmanın en kolay yolu, kendi arabelleğinizi gerçekleştirmektir. İşte basit bir prototip. Programınızda tam olarak bir kez launchIOThread aradığını varsayar. EOF veya diğer IO istisnalarını işlemez, ancak bu kolay olmalıdır.

import Control.Concurrent 
import Control.Concurrent.STM 
import Data.Maybe 
import Control.Monad 

type Buffer = TVar (Maybe Char) 

launchIOThread :: IO Buffer 
launchIOThread = do 
    buf <- atomically $ newTVar Nothing 
    _ <- forkIO $ ioThread buf 
    return buf 

ioThread :: Buffer -> IO() 
ioThread buf = loop where 
    loop = 
    join $ atomically $ do 
     contents <- readTVar buf 
     if isJust contents -- no-one has taken the character yet 
     then retry -- relax 
     else return $ do 
      c <- getChar 
      atomically $ writeTVar buf (Just c) 
      loop 

getChar' :: Buffer -> (Char -> IO()) -> IO (IO()) 
getChar' buf callback = do 
    abortFlag <- atomically $ newTVar False 

    _ <- forkIO $ doGetChar abortFlag 

    return $ atomically $ writeTVar abortFlag True 

    where 
    doGetChar abortFlag = join $ atomically $ do 
     mbC <- readTVar buf 
     abort <- readTVar abortFlag 
     case mbC of 
     Just c -> 
      do writeTVar buf Nothing; return $ callback c 
     Nothing | abort -> return $ return() 
     _ -> retry 
+0

Teşekkürler! STM ve global bir tampon burada kaçınılmaz mı? Ne düşünüyorsunuz, anlambilimden ödün vermeden de 'IO'da tanımlanmalı mı? Düzenleme: Sanırım evet çünkü 'IO' küresel duruma sahip olabilir. –

+0

Neden "getChar" :: (Char -> IO()) -> IO (IO()) '' Prelude' veya 'System.IO'da değil, basit anlambilim var ve tanımlamak imkansız gibi görünüyor merak ediyorum Var olan yapılar ile ('Buffer' parametreniz olmadan). –

+0

1. Evet, Haskell'de global değişkenler yaratmanın yolları var. –

0

Yapmak istediğiniz, istisnalara bakılmaksızın MVAR her zaman güvenli bir durumda bırakılacak şekilde istisna işleme yapıları kullanmaktır. Özellikle, muhtemelen withMVar.

+0

"getChar" ın istisna oluşturmadığını varsaysak bile sorun var, bu yüzden "withMVar" yardımcı olmuyor. –