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 their WorkerSender
  • 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 to recv_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 to recv_burst
  • RecvBurstIterator is non-blocking and holds a mutable reference to its WorkerPool

Modules

Macros

Wrapper around Receiver<DownMsg<T>>::recv, meant to be used in a loop:

Wrapper around Receiver<DownMsg<T>>::try_recv, meant to be used in a loop:

Structs

A message sent from a worker to the manager; contains the timestamp of its creation to allow RecvBurstIterator to stop early.

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”.

A wrapper around Sender<UpMsg<Up>>. This type implements !Send, as RecvAllIterator depends on this type being dropped whenever the thread holding it stops or panics.

Enums

A message sent from the manager to the workers

Type Definitions