12-10-2008 05:14 PM
Solved! Go to Solution.
12-11-2008 04:35 PM
It appears that changing the vi execution priority to "subroutine" causes the timing to look much more like the dll code is in fact running in parallel on two separate threads. Changing all of our dll code to "subroutine" execution priority is somewhat less than desireable though, as this has other side effects such as making the vi's never give up access to the thread until completion which would have other cascading effects. As of right now though, this is the only way I can seem to get the same dll code to run in separate threads.
I was however, able, to produce the desired behavior by creating multiple different dll build specs that reference the same vi's as function prototypes, but rename the prototypes, essentially creating multiple dll's that all have the same code. I could then hardcode in C++ to call a different dll based on the owning thread. While this worked, it is obviously less desirable to have to produce a different dll, lib, and header file for every potential thread that might call our dll concurrently.
Please if anyone has any thoughts or experiences on the topic throw something out here!
12-11-2008 05:39 PM
Hi jhurdus,
I've created a DLL out of LabVIEW code, and I'm calling this DLL multiple times within LabVIEW. I've noticed that I have to enable two options in order to get the DLL code to run in parallel.
1) I have to set the VI that's being made into a DLL to be "reentrant". (File » VI Properties » Execution » Reentrant execution: Preallocate close for each instance)
2) I have to enable each Call Library Function Node thread to "Run in any thread" instead of all of them being restricted to the UI (User Interface) thread. (right-click on Call Library Function Node » Configure... » Thread » Run in any thread)
I'm not sure how to enable the "Run in any thread" option in C++, but I've outlined above how you can do this in LabVIEW. I'll attach my LabVIEW project, code, and DLL for you to test further if you want. (Since the code is in LabVIEW 8.6, I've also attached a screenshot if you have a different version of LabVIEW.)
Kevin S.
Applications Engineer
National Instruments
12-11-2008 08:31 PM
Keep in mind that you'll also need the LabVIEW 8.6 Run-Time Engine in order to run my DLL as well.
Kevin S.
Applications Engineer
National Instruments
12-11-2008 10:29 PM
12-12-2008 09:23 AM
Kevin - I like the idea of replicating the test with a LV wrapper to try to locate the source of the problem! Like you thought, I am running 8.5.1 so I wasn't able to run your example but it was easy enough to replicate. I was also a little wary of your timing code, since your timers are started within the dll code itself. If the locking is happening before callers actually get access to the dll code, then I wasn't sure your code would illustrate the problem. Of course, if the vi took 3 seconds versus 9 seconds to run, it would've been obvious but to make sure i moved the timing measurement outside of the dll by putting each dll call in a timed sequence structure. I've attached pictures of my testing vi so you can see how I set it up.
Anyway, long story short, you are correct! I ran two tests, one where the dll vi was reentrant, one where it was non-reentrant. In both tests the dll was set to "use any thread". When the vi-was re-entrant, each sequence frame took approx 190 ms to complete. Making the vi non-reentrant, sequence frame 1 took approx. 190 ms, sequence frame 2 took 2 x 190 ms, and sequence frame took 3 x 190 ms.
So what the question boils down to is.... how do you specify "run in any thread" when calling the .dll from C++!!!!! I'm not sure on the internal working of the Call Library Node, but could it be sending some input/flag to the dll that is not defined in the dll header file to specify this behavior? Or is it higher level than that? In our c++ code, we are calling the .dll from separate threads, it seems like that is the most logical thing "run in any thread" vs "run in ui thread" would do, that is call the dll functions separately from multiple threads, rather than queue the calls up in a single thread and make them one at a time.
It would be awesome to hear from NI R&D on what's going on underneath the hood here.
Matthew - Good point. Yes, we are aware of that issue. If we can at least enter the .dll in parallel however, we can minimize the resource locking to places only where it has to (i.e. shared memory access) and we can let other things (long array searches that eat up the majority of the execution time) happen in parallel. For these tests though, there are no common sub-vi's, reentrant or non-reentrant.
12-15-2008 05:52 PM
Hi jhurdus,
I've been in touch with R&D, and there don't seem to be any secret flags or options needing to be set in order to run multiple instance of a LabVIEW DLL simultaneously. R&D commented that your DLL may not be fully threadsafe (or specified as reentrant) and/or that you code may be architected in a way such that resources are shared. It sounds like from your previous post that you've taken much of this into account though.
I'll post more if I find additional details.
Does your DLL access hardware at all? What kinds of things do you do in your DLL?
Kevin S.
Applications Engineer
National Instruments
12-15-2008 06:08 PM
Hey Kevin,
I've attached a .zip file with my project and dll VI so that you can verify that the vi does not involve any hardware and has no shared resources (that I am aware of). Any word on what exactly happens in the call library node when "run in any thread" is specified? Does that just mean that LV is making the dll call from separate threads? Knowing what happens in that case would make it easier to try and replicate in c++ to verify that it is possible.
Thanks again,
Jesse
12-16-2008 05:34 AM
jhurdus wrote:Hey Kevin,
I've attached a .zip file with my project and dll VI so that you can verify that the vi does not involve any hardware and has no shared resources (that I am aware of). Any word on what exactly happens in the call library node when "run in any thread" is specified? Does that just mean that LV is making the dll call from separate threads? Knowing what happens in that case would make it easier to try and replicate in c++ to verify that it is possible.
Thanks again,
Jesse
I don't see your DLL_wait.vi being set to be executed as reentrant. Also the project file to build the lockingtest.dll seems not complete: There is no exported function defined.
Rolf Kalbermatter
12-18-2008 02:11 PM
Hi jhurdus,
I know you're working with an NI engineer with this issue, but I still wanted to post an answer to one of your last questions.
When using the Call Library Function Node in LabVIEW, there is the option to select "Run in UI thread" or "Run in any thread". This option, according to the LabVIEW help file (Call Library Function Dialog Box), enables the developer to switch the Call Library Function Node thread from the user interface thread (default setting) to the thread from which the VI is currently executing. Additional details of when you would want to switch the execution thread are in the help file.
Kevin S.
Applications Engineer
National Instruments