Recently, I created 3 new sample message blocks that complement the Agents Library’s existing set and provide additional functionality. The three message blocks I selected to write, priority_buffer, bounded_buffer, and alternator, were based on customer feedback and to improve support for certain scenarios.
Each of these sample message blocks behave similar to unbounded_buffer and the other message blocks in the Agents Library, so taking a quick review at one of my previous posts introducing a couple of blocks might be valuable. Also taking a look at the msdn page for asynchronous message blocks would be helpful.
Priority_buffer is very similar to unbounded_buffer, except messages are sorted and distributed to its targets based on priority. To use a priority_buffer the payload must implement the comparison operator<. This should not be an expensive operation as it will be called often to compare messages. A payload that is less than another is considered to be of higher priority. For example if using a priority_buffer of integers 1 is of higher priority than 2.
Priority_buffer doesn’t collect together and stop messages from being delivered to sort them. Message order will only be changed if messages are not consumed as fast as they are produced. Because messages are prioritized, ordering is no longer guaranteed; priority_buffer will always try to deliver the highest priority message to its targets at any given time.
Scenarios for priority_buffer include providing quality of service by addressing the most important items or tasks first.
Bounded_buffer is like a queue with a maximum capacity. The number of messages a bounded_buffer can hold is specified at construction time. Until it reaches its capacity bounded_buffer performs exactly like unbounded_buffer. Once full bounded_buffer will no longer accept new messages, instead it will postpone any offered messages until it goes back below capacity. Postponing messages is a way for a message block to say it isn’t going to take ownership of this message right now, but might want to at a later point in time. Once back below capacity bounded_buffer will try to consume any of these previously postponed messages from each of its sources. Bounded_buffer should be used in conjunction with the send message passing function to easily quench data production directly at the source without wasting computation cycles using polling.
Bounded_buffer is great in data-flow networks or producer/consumer scenarios where data creation occurs at a faster rate than can be processed and memory is a concern. Using bounded_buffer, message production can be blocked at the source of creation until previous messages are processed.
Many of the blocks in the Agents Library deliver messages out to targets based on linking order; i.e.., the first linked target gets a chance at each message before all others. Sometimes, it is desirable to evenly distribute messages across all targets in a round-robin fashion, alternator does exactly this. Alternator delivers the first message to its first linked target, the second message to its second linked target… and so on looping back to the first link when each target has been offered a message. Think of alternator as an unbounded_buffer that distributes messages fairly amongst its targets.
Alternators are useful for evenly distributing work across multiple pipelines or agents.
Download the Code
Follow this link to download the source code for priority_buffer, bounded_buffer, alternator, and many other samples from the Concurrency Runtime team. Specifically these blocks are located in SamplePack\ConcRTExtras\agents_extras.h.
Please let me know what features you find the most useful and which ones we are lacking. This will help influence what features might be included or discussed in the future.