-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A parallel producer/consumer engine (thread pool) -- -- A parallel producer/consumer engine (thread pool). There are lots of -- features in the Engine, to include dynamically adjustable hooks, -- managed state, and injection points. @package Control-Engine @version 0.0.1 module Control.ThreadPool -- | A trival thread pool for pure functions (mappings). Simply specify the -- number of threads desired and a mutator function. threadPool :: Int -> (a -> b) -> IO (Chan a, Chan b) -- | A trivial thread pool that allows IO mutator functions. Evaluation of -- output is not strict - force evaluation if desired! threadPoolIO :: Int -> (a -> IO b) -> IO (Chan a, Chan b) -- | Implemented here is a thread pool library on crack. - - 1.0 -- Introduction - Typically, a thread pool is a set of execution contexts -- that will execute - tasks from an input queue. Typically, thread pools -- are used to parallize - the processing of incoming work across all -- available CPUs without going - through the expense of starting a new -- thread for every new task. - - In Control.Engine you will -- find a somewhat unique implementation. The - Engine is not only -- a set of threads running a common mutator on the input - queue, -- producing an output queue, but also include hooks, task injection, and -- - state management. - - Hooks :: (a -> IO Maybe a) - Hooks can be -- added and removed during execution without creating a new - engine. -- They allow the developer to modify tasks: - * prior to parallization -- (for sequential preprocessing) - * in parallel, prior to main mutation -- funciton - * in parallel, after mutation function - * post -- parallization (for sequential post processing) - - State Management - -- The stateManager waits for any updates to the mutator state or hooks. -- If any - modifications are made then the new set of hooks (or state) -- is provided - to the workers. This allows the state of the entire -- engine to be atomically - modified (it is all STM) but allows the -- workers to use cheap and quick - MVars. - - The thinking here is that -- changing the hooks and state is a rare / low contention action while -- the need for this information will be constant - and performance -- critical. - - Injection - One injection point allows injection of a -- result that had no preceding - task. With another -- the initial hooks (Input hooks) can be bypassed. module Control.Engine -- | If all you want is a basic thread pool, this will work. You should -- consider using Control.ThreadPool instead. -- -- Evaluation of the result is forced using seq. initSimpleEngine :: Int -> (job -> result) -> IO (Chan job, Chan result) -- | Simpler than calling initEngine, but it allows no state or -- interaction with the hooks and injectors. No strictness is forced. initSimpleEngineIO :: Int -> (job -> IO result) -> IO (Chan job, Chan result) -- | To initilize an engine you must provide: * the number of threads * an -- action that will get the input * an action that will consume output * -- a mutator function to perform on all inputs * an initial state for the -- mutator function -- -- No strictness is forced - be sure you force evaluation if wanted. All -- hooks start out empty. initEngine :: (Eq st) => Int -> (IO job) -> (result -> IO ()) -> (st -> job -> IO (Maybe result)) -> st -> IO (Engine job result st) -- | An Engine represents a pool of threads ready to execute tasks. data Engine job result state Eng :: Chan job -> Chan result -> TVar [Hook state job] -> TVar [Hook state job] -> TVar [Hook state result] -> TVar [Hook state result] -> MVar [Hook state job] -> MVar [Hook state job] -> MVar [Hook state result] -> MVar [Hook state result] -> TVar state -> Engine job result state chan1 :: Engine job result state -> Chan job chan2 :: Engine job result state -> Chan result tvInHook :: Engine job result state -> TVar [Hook state job] tvPreMutateHook :: Engine job result state -> TVar [Hook state job] tvPostMutateHook :: Engine job result state -> TVar [Hook state result] tvOutHook :: Engine job result state -> TVar [Hook state result] mvInHook :: Engine job result state -> MVar [Hook state job] mvPreMutateHook :: Engine job result state -> MVar [Hook state job] mvPostMutateHook :: Engine job result state -> MVar [Hook state result] mvOutHook :: Engine job result state -> MVar [Hook state result] state :: Engine job result state -> TVar state data Hook st msg Hk :: (st -> msg -> IO (Maybe msg)) -> Int -> String -> Hook st msg hkFunc :: Hook st msg -> st -> msg -> IO (Maybe msg) hkPriority :: Hook st msg -> Int hkDescription :: Hook st msg -> String data HookLoc InputHook :: HookLoc PreMutateHook :: HookLoc PostMutateHook :: HookLoc OutputHook :: HookLoc addInputHook :: Engine job result state -> Hook state job -> IO () addOutputHook :: Engine job result state -> Hook state result -> IO () addPreMutateHook :: Engine job result state -> Hook state job -> IO () addPostMutateHook :: Engine job result state -> Hook state result -> IO () delInputHook :: Engine j r s -> String -> IO () delOutputHook :: Engine j r s -> String -> IO () delPreMutateHook :: Engine j r s -> String -> IO () delPostMutateHook :: Engine j r s -> String -> IO () -- | Allows adding tasks that bypass the input hooks. injectPreMutator :: Engine j r s -> j -> IO () -- | Allows bypassing the mutator, meaning a result can be -- produced without a task. This still hits the output hooks. injectPostMutator :: Engine j r s -> r -> IO () instance Eq HookLoc instance Ord HookLoc instance Show HookLoc instance Show (Hook a s) instance Ord (Hook a s) instance Eq (Hook m s)