-
Notifications
You must be signed in to change notification settings - Fork 37
readTQueueN #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
readTQueueN #91
Changes from 5 commits
fe042c6
d17d541
92e7ee7
8696743
ad3e61e
b889299
69742a5
b863196
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,7 @@ module Control.Concurrent.STM.TQueue ( | |
| newTQueue, | ||
| newTQueueIO, | ||
| readTQueue, | ||
| readTQueueN, | ||
| tryReadTQueue, | ||
| flushTQueue, | ||
| peekTQueue, | ||
|
|
@@ -103,6 +104,60 @@ readTQueue (TQueue read write) = do | |
| writeTVar read zs | ||
| return z | ||
|
|
||
|
|
||
| -- Logic of readTQueueN: | ||
| -- +-----------+--------------- +-----------------+ | ||
| -- | write = 0 | write < N-read | write >= N-read | | ||
| -- +--------------+-----------+--------------- +-----------------+ | ||
| -- | read == 0 | retry | retry | case 3 | | ||
| -- | 0 < read < N | retry | retry | case 4 | | ||
| -- +--------------+-----------+--------------- +-----------------+ | ||
| -- | read >= N | . . . . . . . case 1 . . . . . . . . . | | ||
| -- +----=--------------------------------------------------------+ | ||
|
|
||
| -- case 1a: More than N: splitAt N read -> put suffix in read and return prefix | ||
| -- case 1b: Exactly N: Reverse write into read, and return all of the old read | ||
| -- case 2: No longer exists | ||
| -- case 3: Reverse write -> splitAt N, put suffix in read and return prefix | ||
| -- case 4: Like case 3 but prepend read onto return value | ||
|
|
||
| -- |Reads N values, blocking until enough are available. | ||
| -- This is likely never to return if another thread is | ||
| -- blocking on readTQueue. It has quadratic complexity | ||
|
||
| -- in n due to each write triggering readTQueueN to calculate | ||
|
||
| -- the length of the write side as <n items pile up there. | ||
| -- | ||
| -- @since 2.5.4 | ||
| readTQueueN :: TQueue a -> Int -> STM [a] | ||
| readTQueueN (TQueue read write) n = do | ||
| xs <- readTVar read | ||
| let xl = length xs | ||
| if xl > n then do -- case 1a | ||
| let (as,bs) = splitAt n xs | ||
| writeTVar read bs | ||
| pure as | ||
| else if xl == n then do -- case 1b | ||
| ys <- readTVar write | ||
| case ys of | ||
| [] -> do | ||
| writeTVar read [] | ||
| retry | ||
| _ -> do | ||
| let zs = reverse ys | ||
| writeTVar write [] | ||
| writeTVar read zs | ||
| pure xs | ||
| else do | ||
| ys <- readTVar write | ||
| let yl = length ys | ||
| if yl == 0 then | ||
| retry | ||
| else if yl < n - xl then retry | ||
| else do -- cases 3 and 4 | ||
| let (as,bs) = splitAt (n-xl) (reverse ys) | ||
| writeTVar read bs | ||
| pure $ xs <> as | ||
|
|
||
| -- | A version of 'readTQueue' which does not retry. Instead it | ||
| -- returns @Nothing@ if no value is available. | ||
| tryReadTQueue :: TQueue a -> STM (Maybe a) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| {-# LANGUAGE CPP #-} | ||
|
|
||
| {- NB: This one fails for GHC < 7.6 which had a bug exposed via | ||
| nested uses of `orElse` in `stmCommitNestedTransaction` | ||
|
|
||
| This was fixed in GHC via | ||
| f184d9caffa09750ef6a374a7987b9213d6db28e | ||
| -} | ||
|
|
||
| module Stm066 (main) where | ||
|
|
||
| import Control.Concurrent | ||
| import Control.Concurrent.STM | ||
| import Control.Concurrent.STM.TQueue | ||
| import Control.Monad (unless) | ||
|
|
||
| main :: IO () | ||
| main = do | ||
| q <- atomically $ newTQueue | ||
| _ <- forkIO $ atomically $ do | ||
| writeTQueue q (1::Int) | ||
| writeTQueue q 2 | ||
| writeTQueue q 3 | ||
| writeTQueue q 4 | ||
| l <- atomically $ do | ||
| _ <- readTQueueN q 1 | ||
| readTQueueN q 3 | ||
|
|
||
| unless (l == [2,3,4]) $ | ||
| fail (show l) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ test-suite stm | |
| Stm052 | ||
| Stm064 | ||
| Stm065 | ||
| Stm066 | ||
|
|
||
| type: exitcode-stdio-1.0 | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renumber the cases please