2011-06-12 21 views
4

我终于能够追踪我在下降到一个奇怪的错误(至少对我来说)令人惊讶的互动masktimeout之间:为什么`mask_`中和`timeout`?

import System.Timeout 
import Control.Exception 

ack :: Int -> Int -> Int 
ack m n | m == 0, n >= 0 = n + 1 
     | m > 0, n == 0 = ack (m - 1) 1 
     | m > 0, n > 0 = ack (m - 1) (ack m (n - 1)) 

tryack :: Int -> Int -> IO (Maybe Int) 
tryack m n = timeout 100000 {- uS -} $ evaluate $ ack m n 

main :: IO() 
main = do 
    a <- tryack 3 11 
    print a -- Nothing 

    b <- mask_ $ tryack 3 11 
    print b -- Just 16381 after a few seconds 

这在我看来是一个相当“非组成”互动,因为这意味着如果库在内部使用timeout,外部应用mask调用链的某处可能会导致库发生故障。

那么这是(已知的)timeout的执行缺陷还是故意的?

回答

8

mask_做什么?

使用异步异常屏蔽来执行IO计算。也就是说,任何试图用Control.Exception.throwTo在当前线程中引发异常的线程都将被阻塞,直到异步异常再次被解除屏蔽。

timeout是做什么的?

如果在n微秒(1/10^6秒)内没有可用结果,则将IO计算封装超时并返回Nothing。如果在超时到期之前有结果可用,则返回a。 ...一个棘手的实现细节是如何中止IO计算的问题。该组合器在内部依赖于异步异常。

因此... mask_正在阻止timeout提供其例外。就是这样。

你只是不能使用mask并有timeout的工作。

也许更好的方法是使用处理程序来捕获任何东西,但timeout使用的异常?

+1

对,这是不可避免的,因为超时需要计算在当前线程中运行。一个使用超时的库应该可能会派生一个新线程来逃避掩码。 – 2011-06-14 08:12:03

相关问题