2016-10-01 16 views
2

Я пытаюсь использовать hinotify и STM сделать простую концепцию:Ожидание, пока файл перестает быть модифицирована

  • блокировать поток выполнения, пока смотрел файл останавливается не модифицируется
  • Продолжить раз модификации останавливаются или их интервал больше некоторого порогового значения времени (debounces)

В настоящее время я пытаюсь использовать TSem для правильной работы, но я продолжаю работать в любом из этих p roblems:

  • нить не блокирует вообще, и я в конечном итоге удаления hinotify Бодрствующего, прежде чем он даже начинается, бросая исключение
  • поток блокируется на неопределенный срок, в результате чего STM бросить исключение
  • программа печатает 3 раза (3 одновременного уведомление), но только длится в течение 1 секунды, а не 10

кода я написал ниже, и может быть проверен on github, чтобы увидеть для себя.

module Main where 


import System.INotify 
import System.Environment (getArgs) 
import Control.Concurrent (forkIO, threadDelay) 
import Control.Concurrent.STM 
import Control.Concurrent.STM.TSem 
import Control.Concurrent.STM.TVar 
import Control.Monad (forM_) 


main :: IO() 
main = do 
    [file] <- getArgs 


    -- make changes every 1/10th of a second for 10 seconds 
    forkIO $ forM_ [0..100] $ \s -> do 
    appendFile file $ show s 
    threadDelay (second `div` 10) 


    debouncer <- atomically $ newTSem 0 
    notif <- initINotify 
    expectation <- newTVarIO (0 :: Int) 

    watcher <- addWatch notif [Modify] file $ \e -> do 
    e' <- atomically $ do 
     modifyTVar expectation (+1) 
     readTVar expectation 
    print e 
    threadDelay second 
    e'' <- readTVarIO expectation 
    if e' == e'' 
    then atomically $ signalTSem debouncer 
    else pure() 

    atomically $ waitTSem debouncer 
    removeWatch watcher 
    killINotify notif 


second = 1000000 

Вы видите что-то сразу же неправильно с тем, что я пытаюсь сделать?

ответ

1

Должно ли быть STM? Вы можете достичь цели вам с обычными MVar с:

#!/usr/bin/env stack 
{- stack 
    --resolver lts-7.9 
    --install-ghc runghc 
    --package hinotify 
    --package stm 
-} 

import System.INotify 
import System.Environment (getArgs) 
import Control.Concurrent (forkIO, threadDelay) 
import Control.Concurrent.MVar (newMVar, newEmptyMVar, readMVar, swapMVar, putMVar, takeMVar, modifyMVar_) 
import Control.Monad (forM_, forever) 


main :: IO() 
main = do 
    [file] <- getArgs 

    mainBlocker <- newEmptyMVar 
    tickCounter <- newMVar 0 

    -- make changes every 1/10th of a second for 10 seconds 
    forkIO $ forM_ [0..100] $ \s -> do 
    appendFile file $ show s 
    threadDelay (second `div` 10) 


    -- set up file watches 
    notif <- initINotify 
    watcher <- addWatch notif [Modify] file $ \e -> do 
    swapMVar tickCounter 10 
    print "file has been modified; reset ticks to 10" 

    -- 'decreaser' thread 
    forkIO $ forever $ do 
    threadDelay second 
    ticks <- readMVar tickCounter 
    print $ "current ticks in decreaser thread: " ++ show ticks 
    if ticks <= 0 
     then putMVar mainBlocker() 
     else modifyMVar_ tickCounter (\v -> return (v-1)) 


    takeMVar mainBlocker 
    print "exiting..." 
    removeWatch watcher 
    killINotify notif 


second = 1000000 

Идея является «тик» счетчик, который получает значение 10, когда файл был изменен. Отдельный поток пытается подсчитать до 0 и, когда он преуспеет, освобождает блок основного потока.

Если вы используете stack вы можете выполнить код в виде сценария, как это:

stack theCode.hs fileToBeWatched