Jump to content

one producer, two consumers


Recommended Posts

Hello,

I have an application where I am collecting some data with a DAQ card, doing some simple processing, plotting or otherwise displaying a few parameters (some raw, some calculated) at one frequency and logging a few parameters to a file at another, slower frequency. At first I thought it would be best to use one producer loop and two consumer loops, however once one of the consumer loops de-queues an element it would not be available for the other loop. I ended up dividing the loop counter by the multiple of the two frequencies and feeding the remainder to a =0? block and into a case statement - sorry this is hard to explain in words, please see attached block diagram. Is this the best way to do this?

Also, I have used LabVIEW off and on for years but am by no means an expert so any comments on style/functionality etc of my app would be appreciated.

Thanks in advance for your help and suggestions.

Gas Manifold.zip

Link to comment

Hello,

I have an application where I am collecting some data with a DAQ card, doing some simple processing, plotting or otherwise displaying a few parameters (some raw, some calculated) at one frequency and logging a few parameters to a file at another, slower frequency. At first I thought it would be best to use one producer loop and two consumer loops, however once one of the consumer loops de-queues an element it would not be available for the other loop. I ended up dividing the loop counter by the multiple of the two frequencies and feeding the remainder to a =0? block and into a case statement - sorry this is hard to explain in words, please see attached block diagram. Is this the best way to do this?

Also, I have used LabVIEW off and on for years but am by no means an expert so any comments on style/functionality etc of my app would be appreciated.

Thanks in advance for your help and suggestions.

Hi Gator,

I haven't looked at your code but it is standard practice to have one-to-multiple producers to every consumer.

Thus ensuring the consumer receives all messages.

And for this reason (in the case of a standard LabVIEW QSM-PC design pattern) we usually say the consumer owns the queue.

Is there any reason not to have two queues in this case - one for each consumer?

Link to comment

Hello,

I have an application where I am collecting some data with a DAQ card, doing some simple processing, plotting or otherwise displaying a few parameters (some raw, some calculated) at one frequency and logging a few parameters to a file at another, slower frequency. At first I thought it would be best to use one producer loop and two consumer loops, however once one of the consumer loops de-queues an element it would not be available for the other loop. I ended up dividing the loop counter by the multiple of the two frequencies and feeding the remainder to a =0? block and into a case statement - sorry this is hard to explain in words, please see attached block diagram. Is this the best way to do this?

Also, I have used LabVIEW off and on for years but am by no means an expert so any comments on style/functionality etc of my app would be appreciated.

Thanks in advance for your help and suggestions.

User events can be a good solution to the single producer - multiple consumer pattern. The producer fires the user event with the data that you're now putting on the queue and every consumer that has registered for that event and is listening for it will get the same data. You can have anywhere from 1 to n listeners (I don't really know what the upper bound is but it is bound to be large enough). The caveat is that if you have a queue, you're guaranteed a lossless data transfer - if the queue listener is busy, the producer can just add data to the queue or block until space is available and the consumer will always have access to the data until the queue is destroyed. If a producer fires an event and no one is listening, the data just goes to the bit bucket, as far as I know. So, if you use events and you want data integrity make sure your consumer is faster than your producer. You could also use the event time stamps to tell if you missed a data message.

Other wise, I think two queues as suggested would work.

Also, I can't access the code from this machine but I also think your approach as I understand it is valid as well, where you dispatch the queue data after you dequeue it to the correct case for that loop iteration since you don't really need asynchronous processing.

Mark

Link to comment

A few thoughts on your situation:

Simple, but not elegant solution: create one queue for each consumer loop. This definitely is not the most efficient, but It should make your code work (if you're under a deadline). Another quick-n-dirty solution would be to use a chained producer consumer pattern, where the output of one consumer is the input of the next. This may or may not work with your data scenario, and at worst, this devolves into my first suggestion of make two copies of the data.

Hey, memory is cheap, right?

You should also consider block processing methods (think chunks of data rather than individual points): have at least two buffers, fill one buffer (for example, an array), process contents of one buffer (extract aggregate statistics and log to file) all while the other buffer is filling. This could be a queue of arrays. While this is in step with producer-consumer, this is more at the algorithm level than at the architecture level.

- Jon

Link to comment

Or have a look at the design pattern Observer:

Exactly! This sets up publish-subscribe communication, in which multiple subscribers can receive the same published data. LabVIEW supports this (though not necessarily using objects) natively with networked shared variables configured to support RT-FIFOs.

Link to comment

Exactly! This sets up publish-subscribe communication, in which multiple subscribers can receive the same published data. LabVIEW supports this (though not necessarily using objects) natively with networked shared variables configured to support RT-FIFOs.

Thanks for the replies. I decided to go with the division in the consumer loop idea as it seemed the simplest. Having 2 copies of the same queue does not seem very efficient at all.

I don't think the publisher-subscriber link was complete - could you try posting again? Thanks. Id like to look that solution over since I have used it in C#.

One more question: I am trying to use an event structure (in the producer loop) to initialize my output file (set up the header, etc). I then pass the file refnum from the producer to the consumer loop, however since the producer while loop is still running, the refnum gets passed to the producer while loop loop tunnel but goes no further. This causes the consumer loop to NEVER run, I assume since it is missing an input. I have attached my latest code.

Any suggestions? Thanks in advance!

Gas Manifold.zip

Link to comment

Thanks for the replies. I decided to go with the division in the consumer loop idea as it seemed the simplest. Having 2 copies of the same queue does not seem very efficient at all.

I don't think the publisher-subscriber link was complete - could you try posting again? Thanks. Id like to look that solution over since I have used it in C#.

One more question: I am trying to use an event structure (in the producer loop) to initialize my output file (set up the header, etc). I then pass the file refnum from the producer to the consumer loop, however since the producer while loop is still running, the refnum gets passed to the producer while loop loop tunnel but goes no further. This causes the consumer loop to NEVER run, I assume since it is missing an input. I have attached my latest code.

Any suggestions? Thanks in advance!

You are correct - the second loop can't start until the first finishes because there's a direct dataflow dependency between an output of the first loop and an input of the second - so, you need to rethink the program flow. Since all of the data saving is handled by the consumer, the file initialization is probably best handled there as well. And since the consumer loop determines whether or not there's data to save, it could create the file when the log data button is operated and then use an uninitialized shift register to handle the file ref between calls. This is a functional global variable (FGV) in LabVIEW terms. See the GasManifold2.vi in the attachment

Mark

Gas Manifold.zip

Link to comment

Any suggestions?

As your DAQ rate implicitly times the Consumer and it is set to 20 Hz i.e. 50ms then having a Timeout (currently 10ms) in the Consumer means you are executing the No Error case when there is actually no data (or default data) in the queue.

Therefore, your log file will have lots of "default data" entries.

I would suggest explicitly handling the Timeout (or remove it if not needed)

Link to comment

A more low level approach would be to read the data twice from the DAQ device!

post-2399-075737800 1278661952_thumb.png

you should be able to place this code in a Reentrant VI (do not share clones) and you can have multiple places from where you can read data.

I have never tried it but it should work.

Ton

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.