From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Queue: one producer vs multiple consumers

Hi,

This may be a simple question. In my application, I have a master/multiple slaves queue architecture. So the master enqueues messages. Each message is adressed to only one slave. Since all the slaves are waiting after queue elements, they all should receive the message and all dismiss it but one, the destinator. Apparently, it is not working like that. Once the message is dequeued by a slave, it is no more available in the queue and the others are not notified. Is that right?

I could use a seperate queue for each slave, but when it comes to be 100 slaves, I find it a but heavy to manage hundred queues. I tried instead to do a router-like architecture. Everyone is listening and for each message they all verify who is the destinator. Only the destinator processes the message and the other ones simply dismiss it. Is there a way for me to implement that?
Joe
0 Kudos
Message 1 of 16
(5,030 Views)
A quick answer is to use preview rather than dequeue.  If you dequeue it the item is out of the queue so nobody else can get it.  Preview is more like a peek, and if its yours then dequeue it.
Message 2 of 16
(5,022 Views)
Joe,

An enhanced functional global variable could do this. Search for "action engine." The VI will have two data inputs/outputs and a command input. One of the data inputs is the ID or address of the "target" slave. The other is the message. The commands (probably implemented as a type-def enum) might include: Initialize, Write, Read ID, Read message and dismiss, and others as needed. The master would Write. All slaves would periodically Read ID. If a slave finds its own ID, then it performs a Read message and dismiss, which clears the ID and message data elements.

Lynn
0 Kudos
Message 3 of 16
(5,018 Views)
Lynn,

Thank you for your suggestion. The thing is the slaves can also send back data to the master. So everyone, the master and the slaves, can send data through the queue and receive from. Actually, they all are listening and waiting after data destinated to them. Also, the reason why I tried using queue is to avoid polling and minimize CPU resources. Do you think what you suggested can work for me?
Joe
0 Kudos
Message 4 of 16
(5,009 Views)
Lynn,

Do you have any references, sites, post, talking about action engine, the way it works, etc, because so far I can't find any good references.

Also, Evan, thank you for the quick answer. I forgot about preview. This could work for me, but the last time I used that, I had some problems dequeueing what I previewed. But I will try again.
Joe
0 Kudos
Message 5 of 16
(4,999 Views)

It actually sounds like a fairly dicey problem, depending on your need for response times and total messaging bandwidth.  Many of the issues seem to revolve around multiple producers and consumers wanting simultaneous read and write access to a continuously changing entity.  At least that's how it sounded to me, that all the consumers are independent and should be allowed to consume their own messages just as soon as they're able to notice them.

For example:

Consumer #3 performs a preview and discovers that there's a message waiting at position #9.  In order to pull it out of the queue, it must first dequeue the first 8 messages in line.  Then after dequeueing its own message, it must re-enqueue those 1st 8 messages, this time using "Enqueue at Opposite End" to restore the original sequence.

However, before it can finish re-enqueue'ing those 8, Consumer #11 performs a preview and discovers that there's a message at (apparent) position 4.  This really *should* be position 12, but how can Consumer #11 know what #3 is in the middle of?

Meanwhile, one of Consumer #3's 8 messages is addressed to Consumer #11, and it's actually quite important that Consumer #11 gets this one first instead of the one that it just found for itself

And so on...

Now, some (most?  all?)  of this kind of conflict can be resolved through the use of semaphores, but the penalty is that whenever any Consumer is accessing the shared queue, 100's of other Consumers are stuck waiting their turn.  And so all the independence and parallelism you were after in the first place with the producer / consumer pattern starts slipping away...

I haven't personally built an app around a massively parallel messaging architecture.  I hope someone who has gets involved here because I'd like to learn how it's done.  I'd wager there are a few different elegant solutions, but all I can manage to think of are the pitfalls.

-Kevin P.

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 6 of 16
(4,999 Views)
Kevin P.,

Actually, if I should preview, I would only preview the first element in queue. Since one of the consumer, being the destinator, will eventually pop out the element, it is okay.  So that avoids using semaphore and simplifies the thing.


Joe
0 Kudos
Message 7 of 16
(4,994 Views)
Some time ago I went looking for queued messaging architechtures, and ran across the OpenG Commander, put together by a number of the folks at OpenG and managed by Michael Aivaliotis.  Commander's current status seems to be deprecated in favor of a currently closed source system, but the alpha versions are still available at sourceforge.net.

Roughly speaking, it keeps a separate queue for each consumer loop.  The destination of each message is not decided when it arrives, but rather before it is placed on the queue.  That way, consumers only receive messages meant for them.

It's not applicable to every problem, but it is a very flexible design.

Joe Z.
0 Kudos
Message 8 of 16
(4,987 Views)
I started to suggest that a set of named queues with the names passed in an array might be the way to handle this. Then I got interrupted by my real work... Using the Obtain Queue functions in a loop could generate the queues. The producer would index the array, Obtain Queue (which just grabs a reference if the queue already exists, I think), and write to the queue. The consumers would obtain a queue based on the consumers's ID, wait for the queue to have data, then dequeue it. The consumer -> producer responses could be written to one response queue and read only by the producer. The values written to the queue would need to be a cluster of ID and response data so the producer could tell which consumer sent the message.

The "action engine" is a while loop with an uninitialized shift register. It runs one iteration each time it is called. The Command input selects one of several cases of the case structure inside the loop. Using this approach requires polling but gives a lot of flexibility since yu can define the "action" for each case.

Lynn
Message 9 of 16
(4,974 Views)
Underflow,

I thought of it before to have one queue for each slave, but the problem is that the producer wants to receive also messages from its consumers. He would then have to handle one loop for each consumer to wait after each queue. But, in my application, the number of consumer is determined and can change during runtime which makes that solution unapplicable. The only thing I could think of was one big data bus (queue) delivering the data among the master and its slaves. Each new slave would have to "register to the queue" so he could communicate with the master (and if I wanted, to the other slaves too).
Joe
0 Kudos
Message 10 of 16
(4,971 Views)