【发布时间】:2016-06-10 10:31:03
【问题描述】:
我正在尝试测试异步异常下的正确行为。为了使事情具体化,请考虑以下示例,
casMVar :: Eq a => MVar a -> a -> a -> IO Bool
casMVar m old new = do
cur <- takeMVar m
if cur == old
then putMVar m new >> return True
else putMVar m old >> return False
其中不变量是m 不为空。我认为在异步异常下违反了这个不变量,因为这样的异常可能会到达if 表达式。然而,在我的机器上,它不会通过在分叉的casMVar 上抛出异常而暴露出来,并且延迟增加,就像这样,
values :: Maybe (List Bool)
values = action <$> killDelays
where
killDelays = toDelays <$> [-100..100]
toDelays :: Int -> (Int, Int)
toDelays dt = if dt < 0 then (-dt, 0) else (0, dt)
action :: (Int, Int) -> IO (Maybe Bool)
action (s, t) = do
m <- newMVar False
threadId <- forkIO $ threadDelay s >> void (casMVar m False True)
threadDelay t
throwTo threadId ThreadKilled
tryReadMVar m
虽然values 是Just False 的列表与Just True 的列表连接。
有什么方法可以揭露违规行为吗?或者至少增加在 some 机器上暴露违规行为的可能性?我并不是在寻找使这段代码正确的方法,问题纯粹是关于测试。
【问题讨论】:
-
有趣。我会尝试在要测试的代码中添加一些
yields,以便建议/强制线程切换。 -
yield之前的if语句有时会暴露违规行为。 -
您可以根据需要增加插入
threadDelay的概率。 -
这肯定有效。但我不想接触被测代码。
-
您可能可以在
>>=中创建一个执行yield的monad。但总的来说,异常安全性很难测试,正式推理要容易得多。在您的示例中,casMVar的异常安全性取决于异步异常在执行时是否被屏蔽。
标签: haskell exception asynchronous concurrency