等待文件停止修改

时间:2016-10-01 11:15:11

标签: haskell semaphore inotify stm debouncing

我尝试使用hinotify和STM制作一个简单的概念:

  • 阻止执行的线程,直到观看的文件停止被修改
  • 一旦修改停止,或其间隔大于某个时间阈值(去抖动)
  • ,继续

目前,我尝试使用TSem来使其正常工作,但我一直遇到以下任何一个问题:

  • 线程根本没有阻塞,我甚至在它开始之前移除了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 个答案:

答案 0 :(得分:1)

是否必须GrandChild?您可以使用普通refs s:

实现目标
STM

这个想法是一个&#39; tick&#39;每当文件被修改时,计数器设置为10。一个单独的线程尝试倒计数到0,当它成功时,释放主线程的块。

如果你使用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