Add tryWriteTBQueue to Control.Concurrent.STM.TBQueue
I'd like a "try" variant of writeTBQueue, so part of my application can react to the queue overflowing by returning a "queue is full" status.
Attached is a series of patches, the last of which adds
writeTBQueue. The other patches fix a couple minor issues:
- Force capacity computations, so a long series of
readTBQueuecalls won't lead to a stack overflow.
- Guard against negative queue size given to
While we're at it, I have a couple general questions about retry and orElse:
return ())guaranteed to not be interruptible by an asynchronous exception when exceptions are masked?
- Is there a performance benefit to avoiding retry when possible? I'd imagine not, since this should only involve throwing away a few transaction log entries.
return ()) is guaranteed to not be interruptible, and if there is no performance benefit to avoiding retry, then it seems there's little point in having any of the try* functions.
In the documentation for Control.Exception, it lists operations that are guaranteed to not be interruptible. One of them is:
- STM transactions that do not use retry
This is a useful property, and is expected of any "try" function. However,
I did a quick test, and it looks like
return ()) is not interruptible:
import Control.Concurrent import Control.Concurrent.STM import Control.Exception import Control.Monad repeatSTM :: STM () -> IO () repeatSTM = replicateM_ 50000000 . atomically main :: IO () main = do finished <- newEmptyMVar tid <- mask_ $ forkOS $ do repeatSTM (retry `orElse` return ()) putMVar finished () threadDelay 100000 killThread tid -- should wait for the thread to run to completion putStrLn "Let's see if the thread finished..." takeMVar finished putStrLn "Yes, it did."
Is this guaranteed in general? That is, if the transaction does retry calls, but the transaction as a whole does not retry due to orElse, is the transaction guaranteed to not be interruptible?