Expand description
This crate provides the WorkerPool
struct, which lets you manage a set of threads that need to communicate with the parent thread.
Throughout this documentation, the thread owning WorkerPool
is called the “Manager”,
whereas the threads created and handled by the WorkerPool
instance are called “Workers”.
Communication to and from the workers are done using std::sync::mpsc
queues.
When the manager communicates to the workers, the messages are said to go “down”,
and when the workers communicate to the manager, the messages are said to go “up”.
Communication from the workers to the manager uses a SyncSender
wrapped inside of WorkerSender
, as to not overwhelm the manager thread and cause a memory overflow.
WorkerSender::send
can thus block and WorkerSender::try_send
can return Err(TrySendError::Full)
.
Because of the guarantees of WorkerSender
, locking or waiting for the queue to become available will not cause a deadlock when trying to join the threads,
as all the joining methods of WorkerPool
(WorkerPool::stop
and WorkerPool::stop_and_join
) will first empty the message queue before
calling join()
.
This guarantee of absence of deadlocks comes at the cost of restricting what a workers may or may not do:
- if a worker is blocking or looping indefinitely, then it must be able to receive a
Stop
message at any time - once the
Stop
message is received, execution must stop shortly: a worker may only block on the message queue of theirWorkerSender
- downward message queues aren’t bounded, as that might otherwise introduce a deadlock when trying to send the
Stop
message
Additionally, the livelock problem of requests queuing up in the upward channel while the manager thread tries to catch up with them is solved by WorkerPool::recv_burst
:
- any message sent before
recv_burst
was called will be yielded by its returned iterator (RecvBurstIterator
) if it reaches the manager thread in time (otherwise, it’ll sit in the queue until the next call torecv_burst
) - any message sent after
recv_burst
was called will cause that iterator to stop and put the message in a temporary buffer for the next call torecv_burst
RecvBurstIterator
is non-blocking and holds a mutable reference to itsWorkerPool
Modules§
Macros§
- recv_
break - Wrapper around
Receiver<DownMsg<T>>::recv
, meant to be used in a loop: - try_
recv_ break - Wrapper around
Receiver<DownMsg<T>>::try_recv
, meant to be used in a loop:
Structs§
- UpMsg
- A message sent from a worker to the manager; contains the timestamp of its creation to
allow
RecvBurstIterator
to stop early. - Worker
Pool - The main struct, represents a pool of worker. The owner of this struct is the “Manager”, while the threads handled by this struct are the “Workers”.
- Worker
Sender - A wrapper around
Sender<UpMsg<Up>>
. This type implements!Send
, asRecvAllIterator
depends on this type being dropped whenever the thread holding it stops or panics.
Enums§
- DownMsg
- A message sent from the manager to the workers
Type Aliases§
- Receiver
- Recv
Error - Send
Error - Sender
- Sync
Sender - TryRecv
Error - TrySend
Error - Worker
Receiver - A wrapper around Receiver<DownMsg
>