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: 

Response queue from multiple producers

Solved!
Go to solution

In my application I'm working on an API that is queue driven. Multiple different parts of the code can send a "Command" and expect a response.  Obviously if two separate sections of code send a different command at nearly the same time, we have a race condition for the response queue.

 

I have several ideas on how to overcome this (action engine response, preview the queue and look for proper data, semaphores), but I'm wondering if there is a "standard method / best practice" for doing it.  I haven't run in to this problem before.  So far I'm leaning toward semaphores - it seems the simplest solution.  Below is a mockup I did as proof of concept.

 

semaphore.png

 

 

Message 1 of 13
(4,408 Views)

I may be wrong here as my Queue usage has been pretty basic but dosen't the use of Queues eliminate race conditions?

 


@BowenM wrote:

In my application I'm working on an API that is queue driven. Multiple different parts of the code can send a "Command" and expect a response.  Obviously if two separate sections of code send a different command at nearly the same time, we have a race condition for the response queue.

 



Nearly being the key word there, the responses will be loaded in the Queue and removed from the Queue in the order they were received.

========================
=== Engineer Ambiguously ===
========================
0 Kudos
Message 2 of 13
(4,398 Views)

@RTSLVU wrote:

I may be wrong here but dosen't the use of Queues virtually eliminate race conditions?

 


@BowenM wrote:

In my application I'm working on an API that is queue driven. Multiple different parts of the code can send a "Command" and expect a response.  Obviously if two separate sections of code send a different command at nearly the same time, we have a race condition for the response queue.

 



Nearly being the key word there, the responses will be loaded in the Queue and removed from the Queue in the order they were received.


 

 

But I could have two separate loops waiting for the response to be enqueued.  Yes, I could have a separate queue for each response, but that would end up being 80+ queues.  I guess I could have worded my subject slightly differently.  In my head, the API loop is the consumer, but really for the "response" I have a single producer with 80+ consumers.  Each consumer needs to know if the enqueued element is his or someone else's.

0 Kudos
Message 3 of 13
(4,390 Views)

Queues are 1 to 1 or  many to 1.  You don't want to have multiple loops dequeueing from the same queue.

 

Create an array of 80 queues, +1 for the data to be send to the common loop.

 

Each loop puts a command into the queue for the common loop.  It also puts in the queue reference for its response queue.

 

The top loop dequeues an item, unbundles the command and the queue reference, formulates the repsponse and enqueues that response back into the reference it was sent.

 

Think of it as each of the 80 loops sending its own self-addressed, stamped envelope when it sends a message to the common loop.

 

0 Kudos
Message 4 of 13
(4,374 Views)

What I do is have have the producer send a queue reference inside of the command.  Then the consumer just uses that queue reference to send the response.  Each producer will have to maintain its own queue, but no semaphores are needed.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 5 of 13
(4,367 Views)

@RavensFan wrote:

Queues are 1 to 1 or  many to 1.  You don't want to have multiple loops dequeueing from the same queue.

 

Create an array of 80 queues, +1 for the data to be send to the common loop.

 

Each loop puts a command into the queue for the common loop.  It also puts in the queue reference for its response queue.

 

The top loop dequeues an item, unbundles the command and the queue reference, formulates the repsponse and enqueues that response back into the reference it was sent.

 

Think of it as each of the 80 loops sending its own self-addressed, stamped envelope when it sends a message to the common loop.

 


 

I considered this option, but it honestly seems convoluted compared to the above semaphore solution.  If I pass around the array as an array, I need to keep track of which API call has which index in the array. Yes, I could do this with proper documentation (bookmarks, etc) but that seems cumbersome. 

 

I could use a cluster 80+ queues with the proper names so that the code becomes a bit more self documenting.  But then I have some sub-vi that I have to manually initialize and wire in all of these queued elements.  Obviously the cluster would be type defined and would be some big unwieldly front panel item every time I pass it in / out of sub vis.

 

Admittedly there is nothing saying that the response needs to be a queue. I could use a global variable, functional global, etc.  The queue was just for convention, and I will freely admit this is an "improper" use of a queue. The problem is still the same:  How do I get data from one producer to multiple consumers without it being a convoluted unwieldly solution.

0 Kudos
Message 6 of 13
(4,362 Views)
Solution
Accepted by topic author BowenM

@BowenM wrote:

Admittedly there is nothing saying that the response needs to be a queue. I could use a global variable, functional global, etc.  The queue was just for convention, and I will freely admit this is an "improper" use of a queue. The problem is still the same:  How do I get data from one producer to multiple consumers without it being a convoluted unwieldly solution.


Well, if you do not want to embed the return queue in the message, then use a non-reentrant VI that is the only access to sending commands to your consumer.  This VI would send the command and then wait for the response.  Since the VI is non-reentrant, it blocks the other loops until the response is back.  This is a lot cleaner, and likely faster, than using the semaphore.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 7 of 13
(4,349 Views)

I think using the semaphores are far more convoluted.  I think there is a non-zero risk that you can accidentally have the code lock itself up.

 

You don't necessarily need to have an array of references.  An array is my first thought for having an easy way hold X instances of anything.  You'd be able to create 80 queues easily because you can do it in a For loop.

 

You can have each of the loops create its own queue before it starts, closes up its own queue when it ends.  Inside the loop you only have one instance of that wire and that is what you send to the producer.  You don't need an array of need to index a reference out of the array.  The queue reference for a particular loop only exists in the neighborhood of that loop.

 

 

0 Kudos
Message 8 of 13
(4,334 Views)

@RavensFan wrote:

I think using the semaphores are far more convoluted.  I think there is a non-zero risk that you can accidentally have the code lock itself up.

 

You don't necessarily need to have an array of references.  An array is my first thought for having an easy way hold X instances of anything.  You'd be able to create 80 queues easily because you can do it in a For loop.

 

You can have each of the loops create its own queue before it starts, closes up its own queue when it ends.  Inside the loop you only have one instance of that wire and that is what you send to the producer.  You don't need an array of need to index a reference out of the array.  The queue reference for a particular loop only exists in the neighborhood of that loop.

 

 


Oh...  These aren't loops.  They are API wrappers that just enqueue a message and wait for a response.  The wrappers really are going to end up going in to TestStand sequences, and the application allows multiple sequences to be running asynchronously. 

 

I do like crossrulz idea of a non-reentrant VI.  I agree that they would be faster than semaphores.  I'll have to do some playing around with it

0 Kudos
Message 9 of 13
(4,323 Views)

If someone sends me an email, I just hit "reply" and send and email back to the return address in the original email.   I don't need an array or cluster of email addresses, and I certainly don't need a means of "freezing" anyone else who might want to send me a new email till I've replied to the previous one.

0 Kudos
Message 10 of 13
(4,293 Views)