10-15-2010 09:13 AM
Hi all,
Recently I met a problem which forced me to learn some "advanced" aspects of LabView. In my test station there is an I2C equipment. I have 2 applications and I want them to access this equipment simultaneously. The problem is, when app A firstly runs, it opens I2C and get the" handle"; and then app B runs, it doesn't know the handle, at the same time it can't open the I2C equipment either since it is being used.
I did some search on this forum, and I know there are some communication ways like TCP/IP, Shared Variable, Data Socket. Could anybody tell me which one is the best and why?
Besides, can I just simply write the handle in a .txt file for another application to read? I think it sounds too simple but I don't know where it is wrong.
Thanks.
10-15-2010 10:22 AM
10-15-2010 10:57 AM
It's only been an hour since you first posted, you can't expect an immediate response.
In general it's a bad idea to have two programs accessing the same device at the same time, because they may send conflicting commands, or responses from the device may go to the wrong program. A better approach would be for each program to close the handle when it's not in use. If program A has the handle open and program B tries to open it as well, program B should report an error that the device is already in use, and then try again (either after the user confirms the device is available, or after a set period of time). Another option would be to write a small program C that handles all communication with the I2C device and accepts connections (using VI server, or TCP, or some other interprocess communication) from A and B. When either A or B starts it tries to establish communication with C, and if that fails, it runs C. Sharing the handle directly between programs is not a good idea since the handle may not be valid in the other application - for example, if the communication is over a DLL, the DLL may store some state associated with the handle that is only available in the instance of the DLL that created the handle.
10-15-2010 11:34 AM
Nathand,
Thank you very much! I am actually a sort of impatient now since I am being pushed.
"Another option would be to write a small program C that handles all communication with the I2C device and accepts connections (using VI server, or TCP, or some other interprocess communication) from A and B. When either A or B starts it tries to establish communication with C, and if that fails, it runs C. "
About VI server, as far as I know, it is used to call VI source codes rather than .exe. So I am not clear what the relation is between A, B and C, in terms of source codes and .exe files. After compilation, I need independent applications A and B definitely. So is C a third application? It should not be. So C is just a shared folder of source codes between A & B, and then A & B both use VI server to invoke it? Handle preserves inside C? It sounds nice. But why "When either A or B starts it tries to establish communication with C, and if that fails, it runs C."?
"Sharing the handle directly between programs is not a good idea since the handle may not be valid in the other application - for example, if the communication is over a DLL, the DLL may store some state associated with the handle that is only available in the instance of the DLL that created the handle."
This is why I can't simply use a .txt file to store the handle. I got it, but just want to know more details. The "state" will exist in the stack/heap generated by the DLL, like the auto variables inside a function stored in the stack automatically? But if my A & B calles the same .dll, can the stack by the .dll shared by A & B, or still 2 independent ones? It sounds stupid, since every process should has its own memory map, but I just want to confirm, since they call same dll.
Much details. Thank you in advance, Nathan.
10-15-2010 12:03 PM - edited 10-15-2010 12:06 PM
VI server can also call a VI inside of an executable, if VI server is enabled in the INI file for that executable. I'm suggesting that C should be a standalone program that gets and stores the handle to the I2C device, and also has VIs to handle communication to the device using the stored handle. Then applications A and B can use VI server to call the communication functions and receive a response. If A is running a VI inside C, and B tries to run that same VI, B will wait until the VI is available (as LabVIEW does naturally) without any more programming needed. When A or B starts, it attemps to connect to C using VI Server. If the connection fails (returns an error), A or B runs C by using System Exec, waits a few seconds for C to start, then attempts the connection again. I've used this approach (in my case I wanted to isolate a component that crashed frequently from the rest of the system) and it works well.
You can try simply reusing the same handle, but I would not expect it to work reliably. Each instance of a DLL gets its own data space inside the application that calls it; you cannot use variables in a DLL to share data between two applications that both call the same library.
EDIT added: here's a relevant comment from Microsoft: "Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of all the DLLs global and static variables."
10-18-2010 03:21 AM
Nathand,
Thank you for you really show me a direction. Well, I don't want to keep asking details like I am too lazy to try something, but after I read all the related context help and your previous posts regarding this topic (I know it is a highly admirable post, but because it is more about TCP/IP, whereas currently I want to focus on VI Server, I didn't dig in), i must confess there are still too many details I feel confused.
My feeling is NI doesn't elaborate some basic important concepts thoroughly: like "Application Instance" and "VI Server". Let us take the above instance: I build A.EXE and B.EXE, and want them both to communicate with C.EXE. So are there 3 "Application Instances" of A, B, and C, or there is only 1 "Application Instance", i.e. LabView itself?
I care above question, because I found in many articles it pointed out "Run-time Engine" and "Development System" can't share same port. Otherwise there will be error.
http://digital.ni.com/public.nsf/allkb/C32E9CD39E234DFB86256DE1007840B2
I tend to think the whole "LabView" system is an "Application instance" when we "Open Application Reference", since we only input the IP address and port of the VI Server into "Open Application Reference" node, regardless of what VI/project we are interested at. And we must "Run" a VI to set up a "server", other than do configurations in Tool/Options. If we run a .vi, it sets up a VI Server according to development system configuration in Tool/Options; if we run a .exe, it sets up a VI server in run time engine according to .ini file, am I right?
At last, when I use A and B to communicate with C, I found I can connect C.EXE even without running C. If I am using A.vi and B.vi to call "c.vi in C.EXE" via "Call by reference node" following "Open VI Reference" without "Open Application Reference", it really performs as I exactly want - the data is processed in C but shared by A and B. But after I compliled A and B into exe, the connection between A and B is broken, while they both independently communicates with C very well.
I realized that what I am doing is no more than "dynamically load VI", which is far away from inter-process communication. I struggled to find a really good example. This is only valuable thing I got from NI's help regarding this topic:
http://zone.ni.com/devzone/cda/epd/p/id/4475
It works. Fine. I can simulate it.
After knowing the mechanism, my new problem is: how do I organize C.vi well? I want C to do some actions like "read", "write" instructed by A and B. In normal situations, I will do C as event structure, put a button or something. But here event structure will not work -- I send a value to the button will not trigger event. Well there is an alternative to use a loop to look up the button repeatedly, but is it consuming too much CPU time?
A lot of things again......
10-18-2010 12:10 PM
steady wrote:
My feeling is NI doesn't elaborate some basic important concepts thoroughly: like "Application Instance" and "VI Server". Let us take the above instance: I build A.EXE and B.EXE, and want them both to communicate with C.EXE. So are there 3 "Application Instances" of A, B, and C, or there is only 1 "Application Instance", i.e. LabView itself?
There's an explanation of application instances here. In your case, A.exe, B.exe, and C.exe will all be separate application instances. In the development environment, if they are all part of the same project, then they are in the same application instance. If they are each independent projects, then they are separate instances. To use VI server over TCP (which is what you want to do), each instance needs to be on a different port. This shouldn't be a problem because the only instance that actually needs VI server in your situation is C. A and B will only be clients, so they do not need VI server to be enabled.
steady wrote:
I care above question, because I found in many articles it pointed out "Run-time Engine" and "Development System" can't share same port. Otherwise there will be error.
http://digital.ni.com/public.nsf/allkb/C32E9CD39E234DFB86256DE1007840B2
I tend to think the whole "LabView" system is an "Application instance" when we "Open Application Reference", since we only input the IP address and port of the VI Server into "Open Application Reference" node, regardless of what VI/project we are interested at. And we must "Run" a VI to set up a "server", other than do configurations in Tool/Options. If we run a .vi, it sets up a VI Server according to development system configuration in Tool/Options; if we run a .exe, it sets up a VI server in run time engine according to .ini file, am I right?
You can set up VI server for an individual project (or a target in the project), by right-clicking on the target ("My Computer") and choosing properties. This way you can assign different ports to different projects. Also, in a project, the settings for the target will be copied to the INI file when you build an application, so it will work the same way in both LabVIEW and in an executable. You do not need to run a VI to set up VI server, you just need the project or application to be open (it sounds like you've already discovered this). After you open an application reference (using the IP address and port), you then pass that reference to Open VI Reference to get a reference to the specific VI in that instance that you want to run.
steady wrote:
At last, when I use A and B to communicate with C, I found I can connect C.EXE even without running C. If I am using A.vi and B.vi to call "c.vi in C.EXE" via "Call by reference node" following "Open VI Reference" without "Open Application Reference", it really performs as I exactly want - the data is processed in C but shared by A and B. But after I compliled A and B into exe, the connection between A and B is broken, while they both independently communicates with C very well.
In the compiled applications you need to use Open Application Reference first, then Open VI Reference, and finally Call By Reference to execute the VI inside C that shares the data. I don't know enough about your situation to understand why you have a connection between A and B; all of the communication should be routed through C. If A and B need to share a lot of data, why are they separate applications? You could possibly simplify the entire project by making them into a single program with two different main windows.
steady wrote:
After knowing the mechanism, my new problem is: how do I organize C.vi well? I want C to do some actions like "read", "write" instructed by A and B. In normal situations, I will do C as event structure, put a button or something. But here event structure will not work -- I send a value to the button will not trigger event. Well there is an alternative to use a loop to look up the button repeatedly, but is it consuming too much CPU time?
You can use an event structure here with user events, or you can use a notifier or queue, stored inside a shift register in a functional global variable (FGV) inside C. Say when C starts it creates a queue and stores that in a FGV. That FGV also has an action to put data into the queue. A and B connect to C and get a reference to your FGV, which they then use to put command into the queue. Meanwhile, C is waiting for data in the queue; when it receives a command, it process it. The same approach works with a user event, if you prefer that.
Again, I don't know how your program and communication are structured, but it might be simpler to wrap your communication commands in VIs that can be called directly by A and B. I'm guessing that you have a DLL to handle communication with the I2C device, and that you have calls to the DLL to initialize, open a handle, read, write, close, and maybe other commands. You could again create a FGV to store the handle, then create a VI for each of the DLL calls. When C starts it opens the handle and stores it in the FGV. The VI to read gets the handle from the FGV, calls the read command in the DLL, and returns the data. Same idea for write. If you can use this approach you do not need any VI inside C to run continuously, you just need to make sure that C is open so that A and B can connect to it. This gives A and B both almost direct access to the I2C device.
10-19-2010 07:22 AM
nathand wrote:
There's an explanation of application instances here. In your case, A.exe, B.exe, and C.exe will all be separate application instances. In the development environment, if they are all part of the same project, then they are in the same application instance. If they are each independent projects, then they are separate instances. To use VI server over TCP (which is what you want to do), each instance needs to be on a different port. This shouldn't be a problem because the only instance that actually needs VI server in your situation is C. A and B will only be clients, so they do not need VI server to be enabled.
I read the post of the link. Excellent. Much better than the white papers on NI's website. However there is a semantic tanglement: "Labview.exe" sometimes refers to the app generated by user; sometimes it should refer to just the "Labview.exe", which exists where we install the labview software. I am using LV7.1 because the project I am maintaining is written in this version. There is not "project" yet in LV7.1. In development environment, Application Instance is just the "Labview.exe", which is the development software itself. Regardless of what VI i am doing in, if I open application reference at the default port 3363, and query the "App.Name" property, I will get "Labview.exe". Furthermore, even though I am not opening any VI, as long as I open the Labview.exe, if I run my own App.exe within which I connect 3363 at "localhost", I still can get "App.Name" as "Labview.exe".
So at least in LV7.1, "Labview.exe" is the only Application Instance representing all the development environment, whereas each app generated by user has different Application Instance, exactly as you said.
In the compiled applications you need to use Open Application Reference first, then Open VI Reference, and finally Call By Reference to execute the VI inside C that shares the data. I don't know enough about your situation to understand why you have a connection between A and B; all of the communication should be routed through C. If A and B need to share a lot of data, why are they separate applications? You could possibly simplify the entire project by making them into a single program with two different main windows.
Here I mean I was not RUNNING C. C is still an exe but not run. I still can reference the VI inside C by the path like C.exe/C.vi. Forget it, it is no more than dynamical load. A.exe and B.exe will get their own copy of C.vi in their own memory. There is no communication through C after A and B are compiled, although before A and B are compiled, they did communicate through C -- because A and B are in the same application instance I think.
You can use an event structure here with user events, or you can use a notifier or queue, stored inside a shift register in a functional global variable (FGV) inside C. Say when C starts it creates a queue and stores that in a FGV. That FGV also has an action to put data into the queue. A and B connect to C and get a reference to your FGV, which they then use to put command into the queue. Meanwhile, C is waiting for data in the queue; when it receives a command, it process it. The same approach works with a user event, if you prefer that.
Again, I don't know how your program and communication are structured, but it might be simpler to wrap your communication commands in VIs that can be called directly by A and B. I'm guessing that you have a DLL to handle communication with the I2C device, and that you have calls to the DLL to initialize, open a handle, read, write, close, and maybe other commands. You could again create a FGV to store the handle, then create a VI for each of the DLL calls. When C starts it opens the handle and stores it in the FGV. The VI to read gets the handle from the FGV, calls the read command in the DLL, and returns the data. Same idea for write. If you can use this approach you do not need any VI inside C to run continuously, you just need to make sure that C is open so that A and B can connect to it. This gives A and B both almost direct access to the I2C device.
I am doing the I2C stuff exactly as you described. It is a dll of USB/I2C adaptor. The simpler way should be: everytime if I want a I2C read/write, I should start from Open and end up with Close. But the only problem is the overhead of method may be high, especially when the I2C read/write is qutie frequent. So the user wants this kind of functionality: he opens A, and A opens I2C, do read/write stuff; then he opens B, B directly uses the opened port ..... I really doubt if there will be crosstalk. But anyway it is what they want. So I am struggling the "share" stuff now.
Thank you nathand.
10-19-2010 10:48 AM
I should have asked which version of LabVIEW you are using; I almost added a comment to my previous message that application instances did not really exist until LabVIEW 8.0. In 7.1 and earlier, there is only one application instance in the development environment, and of course executables are separate instances.
steady wrote:Here I mean I was not RUNNING C. C is still an exe but not run. I still can reference the VI inside C by the path like C.exe/C.vi. Forget it, it is no more than dynamical load. A.exe and B.exe will get their own copy of C.vi in their own memory. There is no communication through C after A and B are compiled, although before A and B are compiled, they did communicate through C -- because A and B are in the same application instance I think.
I think I understand what's happening now. You are dynamically loading a VI (let's call it "Read.vi") from C.exe into the instances of A.exe and B.exe, rather than opening a reference to a single copy of Read.vi inside C.exe. Newer version of LabVIEW do not allow this; it instead generates an error. As I mentioned, you need to use Open Application Reference to get a reference to C.exe (it just needs to be open, not necessarily running), then pass the application reference to Open VI Reference. Connect a string, not a path, to Open VI Reference containing "Read.vi"; do not provide a path. This will open a reference to the VI of that name inside of C.exe. You also need Read.vi to be loaded into memory when C.exe starts, even if C.exe never directly runs Read.vi. To do this, put a static VI reference to Read.vi somewhere on the block diagram of the top-level VI that is built into C.exe. In 7.1 and earlier you can also put a call to Read.vi inside a case structure, in a case that will never execute (put Read.vi in the True case and wire false to the ?). If done properly, both A and B will get a reference to a single copy of Read.vi running inside C, rather than dynamically loading separate copies of it.
10-20-2010 12:16 PM
As I mentioned, you need to use Open Application Reference to get a reference to C.exe (it just needs to be open, not necessarily running)
This is what I desire: i don't want to run C.exe continuously. I just want A or B to trigger C to do a read/write. Just as I consulted you, if C must being running to reference, I must do a event or queue as you suggested. But now I can just use a FGV structure to run it by A or B. Sweet.
I don't know in which circumstance the Read.vi will not be loaded into memory when C.exe is open? I only think dynamically load vi can lead to this effect, but i guess you don't mean it.