priority-sync 0.1.0.0 → 0.1.0.1
raw patch · 2 files changed
+33/−50 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Tests.hs +12/−12
- priority-sync.cabal +21/−38
Tests.hs view
@@ -140,26 +140,26 @@ atomically $ flip unless retry . (== 0) =<< activity pool withMVar counter $ putStrLn . show -_example1 :: IO ()-_example1 =- do (pool :: TaskPool () ()) <- simpleTaskPool- forkIO $ claim Acquire pool $ putStrLn "Hello world!"- forkIO $ claim Acquire pool $ putStrLn "Goodbye world!"+example :: IO ()+example =+ do let expensiveTask = threadDelay 1000000+ pool <- simpleTaskPool+ forkIO $ claim Acquire (schedule pool 1) $ putStrLn "Task 1 started . . ." >> expensiveTask >> putStrLn "Task 1 completed."+ forkIO $ claim Acquire (schedule pool 3) $ putStrLn "Task 3 started . . ." >> expensiveTask >> putStrLn "Task 3 completed."+ forkIO $ claim Acquire (schedule pool 2) $ putStrLn "Task 2 started . . ." >> expensiveTask >> putStrLn "Task 2 completed."+ threadDelay 100000 -- contrive to wait for all tasks to become enqueued+ putStrLn "Starting pool: " startQueue pool- -_example2 :: IO ()-_example2 =- do prio_pool <- simpleTaskPool- forkIO $ claim Acquire (schedule prio_pool 1) $ putStrLn "Hello world!"- forkIO $ claim Acquire (schedule prio_pool 2) $ putStrLn "Goodbye world!"- startQueue prio_pool+ threadDelay 4000000 -- contrive to wait for all tasks to become dequeued main :: IO () main = do args <- liftM (\args -> if Prelude.null args then ["help"] else args) getArgs let shouldRun s@('s':'t':'r':'e':'s':'s':_) = s `elem` args+ shouldRun "example" = "example" `elem` args shouldRun s = s `elem` args || "all" `elem` args when (shouldRun "help") $ putStrLn "tests: all, testRoom, testMaxThreads, testQueue, testTaskPool, stressInt, stressIntFair, stressInt2, stressUnit, stressUnitFILO, stressUnitFair"+ when (shouldRun "example") $ example when (shouldRun "testRoom") testRoom when (shouldRun "testMaxThreads") testMaxThreads when (shouldRun "testQueue") testQueue
priority-sync.cabal view
@@ -1,5 +1,5 @@ name: priority-sync-version: 0.1.0.0+version: 0.1.0.1 license: BSD3 license-file: LICENSE author: Christopher Lane Hinson@@ -7,54 +7,37 @@ stability: Unstable category: Concurrency-synopsis: Task prioritization.-description: Implements cooperative task prioritization with room synchronization.- .- In the simplest usage, for an unprioritized FILO queue, only three operations are needed: 'simpleTaskPool', 'claim', and 'startQueue'.+synopsis: Cooperative task prioritization.+description: In a simple use case, we want to run some expensive tasks in prioritized order, so that only one task is running on each+ CPU (or hardware thread) at any time. For this simple case, four operations are needed: 'simpleTaskPool', + 'schedule', 'claim', and 'startQueue'. . @- (pool :: TaskPool () ()) <- simpleTaskPool- forkIO $ claim Acquire pool $ putStrLn "Hello world!"- forkIO $ claim Acquire pool $ putStrLn "Goodbye world!"+ let expensiveTask = threadDelay 1000000+ pool <- simpleTaskPool+ forkIO $ claim Acquire (schedule pool 1) $ putStrLn \"Task 1 started . . .\" >> expensiveTask >> putStrLn \"Task 1 completed.\"+ forkIO $ claim Acquire (schedule pool 3) $ putStrLn \"Task 3 started . . .\" >> expensiveTask >> putStrLn \"Task 3 completed.\"+ forkIO $ claim Acquire (schedule pool 2) $ putStrLn \"Task 2 started . . .\" >> expensiveTask >> putStrLn \"Task 2 completed.\"+ threadDelay 100000 -- contrive to wait for all tasks to become enqueued+ putStrLn \"Starting pool: \" startQueue pool+ threadDelay 4000000 -- contrive to wait for all tasks to become dequeued @ .- For a simple prioritized queue, the 'schedule' operation introduces the priority. Prioritization is always least-first.+ A 'TaskPool' combines 'Room's and 'Queue's in an efficient easy-to-use-interface. .- @- prio_pool <- simpleTaskPool- forkIO $ claim Acquire (schedule prio_pool 1) $ putStrLn "Hello world!"- forkIO $ claim Acquire (schedule prio_pool 2) $ putStrLn "Goodbye world!"- startQueue prio_pool- @+ 'Room's provide fully reentrant synchronization to any number of threads based on arbitrary resource constraints.+ For example, the 'Room' from a 'simpleTaskPool' is constrained by 'GHC.numCapabilities'. .- Note that if you run these programs with @+RTS -N2@ or greater, the 'claim' operations may be processed in any order, since 'simpleTaskQueue' detects- the number of capabilities and schedules tasks on each.+ 'Queue's provide task prioritization. A 'Queue' systematically examines (to a configurable depth) all waiting threads with their+ priorities and resource constraints and wakes the most eagerly prioritized thread whose constraints can be satisfied. . 'TaskPool's are not thread pools. The concept is similar to IO Completion Ports. There are no worker threads. If a number of threads are waiting,- the thread that is most likely to be processed next is woken and temporarily serves as a working thread. 'TaskPool's are backed by carefully- written STM (software transactional memory) transactions.- .- A salient feature is that, because any thread can participate, a 'TaskPool' supports both bound threads and threads created with 'forkOnIO'.- .- For applications that have complex resource constraints, it is possible to create a 'Room' to model each constraint. 'Room's are fully reentrant,- and an arbitrary number of threads can 'claim' a 'Room' according to arbitrary rules, or 'RoomConstraint's. In the simple usage above,- a single room represents the number of capabilities available to the GHC runtime.- .- Whenever a thread attempts to acquire a 'Room', a 'Claim' is generated that represents that attempt. The 'Claim' can be approved immediately,- or it can be approved at the whim of another thread that has access to that 'Claim'. This means that 'Room's can be constructed in such- a way that 'Claim's are approved only when a third party thread sees that the resource constraint modeled by that 'Room' has been satisfied.- .- The rules for generating and approving 'Claim's are described by a 'RoomContext'. By default, 'Claim's are approved immediately if their- associated 'RoomConstraint's have been satisfied, but when a 'TaskPool' is introduced approval is deferred for prioritization.- .- 'Room' constraints are completely advisory: any task may claim any 'Room' without restriction at any time by using the 'UnconstrainedRoomContext'.+ the thread that is most likely to be processed next is woken and temporarily serves as a working thread. .- 'Queue's are used to prioritize tasks. Even if you have no need for prioritization, a 'Queue' ensures that only one thread is woken up- when a 'Room' becomes available. A 'Queue' systematically examines to a configurable depth all waiting threads with their priorities- and constraints and wakes the most eagerly prioritized thread whose constraints can be satisfied.+ 'Room's, 'Queue's, and 'TaskPool's are backed by carefully written STM (software transactional memory) transactions. .- A 'TaskPool' combines 'Room's and 'Queue's in an efficient, easy-to-use interface.+ A salient feature is that, because any thread can participate, a 'TaskPool' supports both bound threads and threads created with 'forkOnIO'. . The git repository is available at <http://www.downstairspeople.org/git/priority-sync.git>.