Jump to content

Recommended Posts

A previous post about sharing a FG between two separate LabVIEW projects (or computers) got me thinking about an example I had been working on, but at some point I lost some focus on it. I thought I'd throw it out here in case it helps or interests anyone, and hopefully to get some solid feedback on how the idea could be made better and more applicable.

The idea is to wrap the LabVIEW Queue functions into a library that allows users to share queue-based data over a network with basically the same API as the normal Queues. In the example I'll post below there are only a few differences between regular queues and the new Network Queue:

  1. Network queues only transmit variant data. Users would have to wrap the functions to get specific data types in and out, but it wouldn't be hard.
  2. There are two functions to obtain the queue instead of one. There is Obtain Queue (Client) and Obtain Queue (Server). There is one and only one server where the actual queue is hosted, and there can be any number of remote or local clients.
  3. In the current architecture, if a client calls a function that blocks (like trying to dequeue from an empty queue with a timeout), then all other function calls from that same client will also block until that one completes, even if they wouldn't normally block (like a Flush or Get Status function). This is because there's only one pipeline for all function calls for each specific client.
  4. I'm using LabVIEW Classes, which restricts the functions from being used on RT. There's no particular reason other than encapsulation that I'm using LVOOP, so we could strip that dependency out.

So there are a few limitations, but basically it's a pretty useful library that makes it pretty simple to share data, distribute data over Producer/Consumer type design patterns, and so on, without having to use Shared Variables which for the most part have the same limitations and dangers as regular Global Variables.

So take a look at the attached class. It's meant to be extracted into user.lib. It's written in LabVIEW 8.5. Please let me know what you think! ;)

Network_Queue_Class.zip

Edited by Michael Aivaliotis
Added missing attachment.
  • Like 1
Link to post

That's a great idea. I really can't comment on the code (other than that it looks good) because I didn't look deeply into it.

Stupid question - wouldn't the implementation be simpler if you used wrappers for the queue functions and then used remote CBR calls to call those wrappers like shown in the other thread?

Link to post

Thx for sharing your code. Looks nice and I think I´ll play with it when I got time.

Just one thing I noticed while browsing the code. The timeout "Read TCP Data.vi" is only wired to the first TCP-Read. Although in normal conditions it shouldn´t make a difference.

Link to post

QUOTE (Götz Becker @ Jun 1 2008, 01:54 PM)

Yes, that's one piece that isn't implemented quite correctly. There's really two timeouts that should be accounted for, the timeout for sending the TCP data and the timeout for processing the queue command. Theoretically these should probably be added together into one composite timeout.

QUOTE (Yen @ Jun 1 2008, 11:55 AM)

Stupid question - wouldn't the implementation be simpler if you used wrappers for the queue functions and then used remote CBR calls to call those wrappers like shown in the other thread?

That's an interesting idea. I'll think about it. You'd have the overhead of VI Server calls, but my implementation has its own overhead as well. You'd also have to think about the reentrancy of the wrappers, so that multiple clients could have parallel access to the server's queue resources. Just a thought...

Link to post

QUOTE (ragglefrock @ Jun 1 2008, 06:18 PM)

That's an interesting idea. I'll think about it. You'd have the overhead of VI Server calls, but my implementation has its own overhead as well. You'd also have to think about the reentrancy of the wrappers, so that multiple clients could have parallel access to the server's queue resources. Just a thought...

Actually I think the Call By Reference call will handle arbitration nicely so if you can provide VIs with atomic access to a particular queue you should be fine.

Rolf Kalbermatter

  • Like 1
Link to post

QUOTE (rolfk @ Jun 6 2008, 01:31 AM)

Actually I think the Call By Reference call will handle arbitration nicely so if you can provide VIs with atomic access to a particular queue you should be fine.

Rolf Kalbermatter

One subtle note of caution:

Make sure the queue is not created by the VI that is the target of the CBR. If the connection fails and the target VI is not active in any other running code, LV will clean-up the resource of that VI including the queue it created. This means your queue would go invalid when a network interuption occurs. (This was observed in LV 6.1 with the queue running on a cFP running RT).

Ben

Link to post

QUOTE (neB @ Jun 6 2008, 07:53 AM)

One subtle note of caution:

Make sure the queue is not created by the VI that is the target of the CBR. If the connection fails and the target VI is not active in any other running code, LV will clean-up the resource of that VI including the queue it created. This means your queue would go invalid when a network interuption occurs. (This was observed in LV 6.1 with the queue running on a cFP running RT).

Ben

You are of course right. Creation of any refnumed objects in LabVIEW has to be done in the context of a VI hierarchy that does not go idle for the life time of the refnum. In this case the best thing would be to have a deamon running in the background that gets instantiated if necessary by the remote queue VIs and takes care of queue creation on behalf of the those remote queue VIs.

Rolf Kalbermatter

  • Like 1
Link to post

QUOTE (rolfk @ Jun 6 2008, 12:31 AM)

Actually I think the Call By Reference call will handle arbitration nicely so if you can provide VIs with atomic access to a particular queue you should be fine.

Rolf Kalbermatter

Here was my worry:

Suppose the server creates two queues, A and B, with one or more clients connected to those queues. The server has a set of wrapper VIs (let's suppose for now they're non-reentrant) to access all its queue data. Suppose queue A is full and B is only half full. A client tries to enqueue an item into A with infinite timeout, so it blocks. Another client tries to enqueue an item into B, which should succeed, but the wrapper VI on the server is blocking on A, so B has to wait for access.

It seems to me, to allow full parallel access to multiple queue resources, we'd need one reentrant set of queue wrapper VIs instantiated per queue. Still, this does seem better in many ways than dealing with all the threading and TCP manually.

Link to post

QUOTE (rolfk @ Jun 6 2008, 12:31 AM)

Actually I think the Call By Reference call will handle arbitration nicely so if you can provide VIs with atomic access to a particular queue you should be fine.

Rolf Kalbermatter

OK, I've answered my own question regarding this worry. The easiest thing to do it seems would be to make the wrapper VIs on the server that access the actual queue resource Reentrant with Shared Clones (supposing you have LV85). This makes life so much easier! :)

This allows the client to simply open a regular remote reference to the wrapper VIs without thinking about whether additional instances ever need to be opened. The server is in charge of opening additional instances as needed. For instance, if one client is blocking trying to enqueue data into a full queue, and another client tries to enqueue data onto an empty queue, the server will open another instance of the local enqueue VI. It's pretty awesome...

Attached are the examples I put together. There's only a subset of the queue functions, but the idea is easily extendable. One assumption I made is that the server VIs must be in memory before the client tries to access them.

Link to post

QUOTE (Yen @ Jun 7 2008, 03:11 PM)

I was certain of that as well, but it seems that is not accurate. You can see that by running the attached VIs (8.0, but I'm pretty sure I saw the same in 7.0). If you stop the one which created the queue, the queue still exists. You can even have another VI which will write to it just to see that.

These do look much simpler and that requirement seems reasonable, but you might wish to wrap it and output a nice error.

I don't think that's a valid test. You're opening two references to the queue, so even if you stop one of the VIs and let it go idle (or even close it), you still have a top-level VI running that has a reference to the queue.

I couldn't manage to create a VI that failed, but I believe the danger is if you only use Obtain Queue once from a VI that eventually goes idle, then that queue reference won't stay valid in other parts of the program that continue running after the VI that created the queue goes idle. But again, I tried to reproduce this and was unable...

Link to post

QUOTE (ragglefrock @ Jun 9 2008, 11:08 AM)

I don't think that's a valid test. You're opening two references to the queue, so even if you stop one of the VIs and let it go idle (or even close it), you still have a top-level VI running that has a reference to the queue.

I couldn't manage to create a VI that failed, but I believe the danger is if you only use Obtain Queue once from a VI that eventually goes idle, then that queue reference won't stay valid in other parts of the program that continue running after the VI that created the queue goes idle. But again, I tried to reproduce this and was unable...

Notes on how I got the queue to fail in LV 6.1

The VI that created the queue was a top level VI that was only loaded into memory when the Windows machine opened it. The top level VI was an action engine where the first action was "Init" creating the queue". Latter calls invoked other actions including reading from the queue. When the ref to the top (crator) went invalid due to network timeout, the queue went invalid.

At least that is what my memory tells me.

Ben

Link to post

QUOTE (ragglefrock @ Jun 9 2008, 06:08 PM)

I don't think that's a valid test. You're opening two references to the queue...

Ah, yes, that would make sense, and I knew there was a reason I was sure of it.

Creating the test should be simple - just pass the reference using a global. The reason you couldn't test it is because you probably missed a subtle point - the thing that maintains the reference is not the VI, but the hierarchy. You have to remove the top level VI in the hierarchy from memory. This mistake is easy to make when using LV2 globals - if you create the reference in one hierarchy and then use it in another, it will go invalid if the first hierarchy is removed, even though you keep using the same VI.

I can't test this at the moment, but I ran into this myself in the past as well, so that explanation should hold and would expain Ben's example.

Link to post
  • 5 months later...

I'm playing with the Network Queue VI Server example. So far a Server Example.vi is ran by itself in development environment everithing works fine, Client Example.vi may run by itself, in the project or built executable. As soon as I build executable for the Server or even run it in their project, I get error 1004 "The VI is not in memory." I tried both at local host or different machines. Appropriate IPs are defined in Tools>Options>VI Server:Machine Access.

What I'm missing?

Link to post

I can't look at the code at the moment, but presumably that means that somewhere a VI reference is opened by name, and the code expects you to have the VI already in memory. If nothing in your code calls the VI, it will not be added to the executable and therefore will not be in memory. Look for the Open VI Reference function to see which VI it expects or possibly at the details of the error.

You should probably be able to work around this by adding it to the list of VIs in the build explicitly, but that depends on how that VI is expected to work.

Link to post

QUOTE (skof @ Nov 27 2008, 05:29 PM)

I'm playing with the Network Queue VI Server example. So far a Server Example.vi is ran by itself in development environment everithing works fine, Client Example.vi may run by itself, in the project or built executable. As soon as I build executable for the Server or even run it in their project, I get error 1004 "The VI is not in memory." I tried both at local host or different machines. Appropriate IPs are defined in Tools>Options>VI Server:Machine Access.

What I'm missing?

Another possibility is that you target the wrong application instance. Since LabVIEW 8.0 a LabVIEW process can have many application instances with one main instance and then one additional instance for each possible target in every single project. Of course they don't always remain on the same host (RT target in a project) and consequently have different IP nummers to open first. But when I was deploying a project to a cFP controller recently and tried to access a VI through VI server that existed in this project I got this error too.

Solution was to explicitedly configure VI server in the target of my project to use a different IP port and connect to that. This did kill my performance though so badly that I had to abandone this approach. I guess there is a default VI server on a RT target (as I could connect to it) but a directly deployed application from a project gets instantiated in its own application instance that has to be enabled first.

Rolf Kalbermatter

  • Like 1
Link to post

Yair, Rolf,

my point is that the above Network Queue VI Server example works fine out of Labview project but doesn't work in a project or as built application. I'm trying to figure out what's wrong can be with the project. Does somebody try to use the attached Network Queue VI Server code in a project? This code is useless for me if I can not include it in built application. :(

Link to post

I didn't look at the code, but it was mentioned in the thread that the client assumes that the server VI is in memory, so you might have to make sure it's in the build and that it's set to run, as I've said before. It really depends on how the code is used.

Alternatively, it's possible that you have a problem with the VI server ports. If your EXE has the same VI server port as LabVIEW, it will open a connection to itself. You should specify different ports for the EXE and the dev environment. This is explained in more details in the thread which was mentioned at the beginning of this thread.

Link to post

QUOTE (Yair @ Dec 2 2008, 12:49 PM)

I didn't look at the code, but it was mentioned in the thread that the client assumes that the server VI is in memory, so you might have to make sure it's in the build and that it's set to run, as I've said before. It really depends on how the code is used.

Alternatively, it's possible that you have a problem with the VI server ports. If your EXE has the same VI server port as LabVIEW, it will open a connection to itself. You should specify different ports for the EXE and the dev environment. This is explained in more details in the thread which was mentioned at the beginning of this thread.

Thank you Yair, I had wrong VI server settings for the project (port and machine access list).

May I ask one more question? Is it a way to change VI server port dynamically at runtime when I start an executable? Say, if I need to start several instances of server with one exe.

Link to post
  • 5 months later...

Hey,

I'm using the Networkqueue-vi's from ragglefrock and I must say it 's a really nice code. But the programm i use them in is quiet complex and when sending data from one computer to another via the networtkqueues the transfer is pretty slow and the queues run full of elements.

I tryed to use them in simple vis and it turned out that even then I can only pass data nicly at a rate of 1Hz which is far to slow for my application.

Is there anybody who had a similar problem or does anyone have a suggestion what might go wrong and how I can fix it?

It would be very helpful!!

Thanks in advance

Sonny

Link to post

QUOTE (Sonny @ May 12 2009, 04:57 AM)

Hey,

I'm using the Networkqueue-vi's from ragglefrock and I must say it 's a really nice code. But the programm i use them in is quiet complex and when sending data from one computer to another via the networtkqueues the transfer is pretty slow and the queues run full of elements.

I tryed to use them in simple vis and it turned out that even then I can only pass data nicly at a rate of 1Hz which is far to slow for my application.

Is there anybody who had a similar problem or does anyone have a suggestion what might go wrong and how I can fix it?

It would be very helpful!!

Thanks in advance

Sonny

Can you post a screen shot of your code? This sounds more like an issue with how you are reading or waiting on the queue rather than an issue with the queues themselves. We have been using them extensively and have not seen any of the issues you describe.

Link to post

QUOTE (Sonny @ May 12 2009, 04:57 AM)

Hey,

I'm using the Networkqueue-vi's from ragglefrock and I must say it 's a really nice code. But the programm i use them in is quiet complex and when sending data from one computer to another via the networtkqueues the transfer is pretty slow and the queues run full of elements.

I tryed to use them in simple vis and it turned out that even then I can only pass data nicly at a rate of 1Hz which is far to slow for my application.

Is there anybody who had a similar problem or does anyone have a suggestion what might go wrong and how I can fix it?

It would be very helpful!!

Thanks in advance

Sonny

I think due to the nature of the VI Server implementation, there's simply a high overhead of making the queue function calls. You can likely transfer data faster by building larger packets of data and reading the queue less often. For instance, if you are sending arrays of doubles, try sending 10k at a time instead of 1k. Sending the data itself is not as likely to be the slowdown as the remote function calls.

If you are not sending arrays but rather clusters over the queue, consider making the queue send arrays of those clusters at a time. Or try flushing the queue periodically instead of just reading one packet at a time.

I didn't do any official benchmarks, but the size of the data packet transferred was very much related to the total bandwidth possible.

Link to post

Thanks for the quick reply!!

I post some screenshots of the simple VIs where i tried to use the network queues. It's really simple, It just counts upwards in steps of 100 and the data are read from the network queue on another computer, so the amount of data isn't that high anyway. As you see, shortly after a few seconds the network queue is already quiet full.

Is there anything wrong on how i use the queues?

Link to post

Based on the screen shots you posted your will never process your queues faster than 100ms per item. You have waits in your processing loop which will gate your performance. Since you are using the networks queues there really isn't a need to have the additional waits. The queues themselves and the TCP functions they use all have there own timeouts. Simply use those and take the appropriate action when a timeout does occur. Thus can simply be ignoring the timeout and going back to check for more data in the queue or the extreme case which would be to abort your application. Another alternative is to not include a timeout value (essentially a wait forever) on your queue. If you do this though you will need some external piece of code which will destory the queue allowing the code waiting un it to exit with an error.

Link to post

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.