-
Posts
1,256 -
Joined
-
Last visited
-
Days Won
29
Content Type
Profiles
Forums
Downloads
Gallery
Posts posted by asbo
-
-
hooovahh, I had the distinct impression that this was handled correctly in the TDMS viewer you were working. Am I wrong? I feel like we had a discussion about this exact issue and I was totally expecting you to drop in with a couple magical property nodes.
-
Well, out of curiosity I did spend a few hours on this. But it seems Windows is effectively denying every cooperation in making this functionality work from within LabVIEW. I can create a small Windows executable that uses the functions to assign an imagelist and the thumbbar definitions for the tumbbar buttons just fine, and I can use most of the other TaskBarList methods from within LabVIEW easily such as the Progress Bar functionality but any attempt to set the imagelist for the buttons from within LabVIEW fails with a very useless E_FAIL error message. Not sure what that would be really.
Disappointing that you were stone-walled. Any interest in making the code public domain for tinkering?
I think this feature can be very useful:
At the moment all the open LV windows look exactly the same no matter if they are BD or FP or even if they were opened from different LV versions.
Once this option will be available we could have a list of open vis with the icon from the connector pane next to each vi with different background color for BD and for FP and a number with the LV version.
Besides that, we could have a preview of the vi and even an option to see its status (running/broken/clone/properties/type).
What you're talking about is actually a feature for the LabVIEW IDE, not LabVIEW applications.
-
Interesting. Do you have any benchmarks for the improvement?
-
I don't think this code will work the way you expect. As written, if you have four active modules then the first module that shuts down empties the queue and releases the .Net reference. In the cleanup code you're dequeuing the (one) element and immediately checking the queue status. It's going to return a count of zero.
A SEQ may seem great to implement a storage of a singleton object without having to do a separate VI, but if you need any kind of control over this objects lifetime, a FGV is the preferred choice since it allows implementing the lifetime management inside the FGV without the danger of creating race conditions.
It looks like both you of missed that Option 3 no longer utilizes a SEQ - every module which starts enqueues a copy of the .NET reference on the queue. The point of this is that it lets me utilize the number of elements on the queue as an indicator of how many modules are running. What is still fundamentally missing is semaphores around the queue operations (which would be more correctly refactored into a FGV as rolfk mentioned).
I can't right now, but I'll digest the rest of your posts later.
-
There is in the sample code you posted because you're creating the .Net reference before obtaining the queue. It's easily fixed by creating the .Net reference in a case statement after obtaining the queue if the queue was newly created, along with the code to enqueue the refnum the first time.
Actually, that's exactly how I implemented it.
The returned .Net object is a singleton?Actually, I'm not sure. I'm kind of black-boxing at this point, and also marginalizing that question because it's very unlikely to be a problem in my use case - what I said about modules coming in and out at any time isn't /completely/ accurate, there will be some semblance of order during inits.
Okay, so here's my implementation of Option 3; first Init, then Close:
There is a small-ish race condition in the shutdown that I noticed when writing this up. Assume a last existing module A is shutting down while a new module B is starting up. If B obtains the queue (this, created? = false) between when A queues the last reference and when A releases the queue, B will wait indefinitely on the Dequeue call in the False case of the Init process as there will never be an element to dequeue (unless another module starts up). This is remedied by getting the queue status during Init and running the True case if there are zero elements on the queue.
Thoughts?
-
Is the Composable API of any help? It allows you lower-level access to C series modules.
-
- Popular Post
- Popular Post
-
I believe this is intentional behavior in asbo's code. During initialization each module checks to see if the .Net reference exists. If it does not, the module creates it. Presumably persisting the .Net refnum when no modules need it isn't necessary. I can imagine situations where one might choose to use that strategy. Maybe a db connection or some other resource bottleneck. I am curious what kind of data this .Net refnum represents...
That is correct. The .NET refnum shouldn't persist because there will nothing to clean it up if the last module doesn't take care of it. In this case, the .NET reference is for a factory for a USB driver which handles device filtering and identification. Design constraints don't allow each module to have their own instance of the factory, so all modules in existence must share whatever one exists. If it doesn't exist, the module creates it and uses the queue to make it public.
The fundamental problem causing the race conditions is the test for clean up and the clean up itself is not an atomic operation. There's always the chance Module 2 will do something--after Module 1 tests for cleanup but before the cleanup is performed--that will make the test results invalid. Depending on the circumstances and implementation you'll end up with either a memory leak or dangling reference.
FWIW, I ended up implementing Option 3, which I'm pretty certain defeats the clean-up race conditions and there's only one at start-up (which is actually present in all the options) that two modules might try to create their own factory. In this instance, I think it's a noop because the .NET assembly /should/ return the same refnum it already dished out. If Option 3 isn't clear, I can draft an example real quickly for illustration.
-
-
What does S.E.A have to say about it?
-
Very interesting. Almost makes me wish I still did web development so I had something to play with. Playing with other people's code is less exciting.
-
-
Then you don't need a count because you know there is always 1 Queue reference.
I guess I haven't been clear. There is a single, named queue (of questionable length) but multiple VIs will obtain it - this is what leads to the terminology "multiple references." What I ultimately need is whether the queue is still valid in any context which is determined by a count of how many different contexts are subscribed.
The data (the .NET reference) won't be destroyed until you explicitly call the "Destroy" method in the wrapper. The only thing each call destroys is the Queue reference and then only if the queue already exists. This means that the Queue wrapper can be called from anywhere in the app,by any modules, in any order and will always maintain the queue with a single reference (which keeps the data alive). Your .NET reference will be fine but you won't have to count anything or worry about releasing anything as the Queue reference is created and destroyed, on demand, without destroying the data.
Technically, your first sentence is correct, but's irrelevant if I release all the queue handles because I no longer have access to the .NET reference (and presumably it is automatically cleaned up, eventually). I completely understand that releasing the queue has no direct on the .NET reference, but again, this is irrelevant if I can no longer dequeue the .NET reference to act on it. If I were maintaining a reference to the .NET object anywhere else but this queue, that'd be great; however, the reference is only peek'd from the queue when it is needed and never passed around. There is no common place to keep the queue reference open, as the modules may drop in and out of existence at any time. So, ultimately, it's not about the data (.NET reference) accidentally being destroyed, it's about correctly disposing of the .NET reference when no one else is interested, while also making it publicly available when one or more modules are interested.
Hopefully that is more clear?
-
Typically one of the registers (EBX) has the pointer to the VI's "dataspace" but that data structure is undocumented and version specific.
For now...
-
No.1 won't work since if the queue is not created, you don't know if it's the last one or not (there may be 10)
I'm not sure I understand what you're saying, but the modules will never try to clean-up without having initialized. During cleanup, the module knows the queue must exist because it (the module) will have created it during initialization.
I wrote this up quickly for illustration's sake:
There is a No.4
Only allow 1 queue reference so that you do not need to count. This is the method I use which means that you only have to call "Destroy" at the end of everything (it also means you don't get "runaway references").
This doesn't work for my scenario because the .NET reference needs to be concurrently accessible between modules and cannot be destroyed/re-created in the interim.
In terms of wrapping your own, is the extensible session framework any use? This already has it all wrapped up already including this counter.
I hadn't heard of this before but I'll take a look at it. It's probably too heavy for this implementation (which ultimately revealed to me that the .NET reference in question actually deserved its own LV class).
I think no matter the method, this is impossible to do without a race condition.
-
In reality, the .NET actually represents what should be another LV class, but up until this point it was unnecessary to encapsulate it that way with its own Create/Destroy methods called by the class which utilizes it. And now, of course, it doesn't make sense to spend the time on that encapsulation because it needs to Just Work.
-
I just bounced this question off an AE, but I thought I might try the think tank as well: I have a named SEQ that holds a .NET reference shared by several modules; when releasing the queue in any of these modules I'd like to know if the queue was destroyed so I can also clean up my .NET reference as well.
I can:
1) re-open the queue and see if it was created and react on that, or
2) wrap the Obtain/Release functions and have my own counter, or
3) re-enqueue the reference every time I obtain the queue to piggy-back the Get Queue State node to see the number of times its been obtained (this kills the SEQ).
I'm not thrilled about any of these options - I would have sworn on some holy literature that some of the Release functions passed back that kind of information but looking now I can't find one that does.
Is this a flawed paradigm?
-
Can you build a debug executable, connect to it, and then use the built-in profiler to see if any VIs crop up with large memory usage?
-
The KB article doesn't list a fixed software release, so I would reach out to NI and find out if it's been addressed and the article is just out of date.
-
It is okay to use Scan Engine variables in your host application (I think they get published as network variables?), but I have little exposure to them so that's all I can say.
For the latter problem, have you tried a force re-compile? Someone else posted about that particular error on these forums a bit ago, but I forget who/when/where. I've seen this dialog (outside of the LabVIEW context) tied to hard drive corruption (run chkdsk /f?). Try pulling another copy out of version control and see if it still presents.
-
Do you have a bunch of loops which don't have a 0ms wait in them to yield the CPU? Acceptable alternatives are event structures, ms internal nodes, or most any NI-built node which includes a timeout terminal.
For loops or while loops without a node like these will be free-running, executing literally as fast as the scheduler will allow, which is often not necessary and detrimental to the performance of the application as a whole.
-
You might try JKI support on this one.
Personally, I'd uninstall it, make sure there's nothing left in AppData, ProgramData, or Program Files, and then reinstall. You can preserve most of the cache folder if you don't want to lose your library in doing so.
-
edit: you said shell notify, i got mixed up! Either way, the notify icon is pretty cool so I'll leave my shpeal even though it is a bit unrelated!
There's a couple over on NI.com... One uses a CVI interface (blech), one uses a .NET assembly (which I forgot about), and there may be one more floating around. Maybe I haven't seen the one you're referring to, feel free to post it up.
I really enjoy interfacing with external code in LabVIEW (weird, I know), so I wanted to try an implementation which only used Win32 API calls, just for sport.
From what I read on MDSN it is fairly easy to do that from C/C++. You just want to use the ITaskBar3 interface in shobjidl.h. A single call to
// Create an instance of ITaskbarList3 ITaskBarList3 *ptbl; HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ptbl); [/CODE]
The sad thing is the there's still a bit of work there, especially depending on what the IID_PPV_ARGS() macro does. Plus, any time I use API constants I like to make a ring or enum to make the implementation clean; usually I crack open Visual Studio to make that easier. I wonder how useful it would be to have a LabVIEW module which can parse C/C++ includes and let you lookup defines and constants by name. Obviously, you'd have to dance around datatypes, but still...
-
I'm curious to what end you're seeking this. I have only ever written test and measurement applications, never software products, in LabVIEW; none of which would benefit from (or would it be functionally appropriate to have) taskbar controls.
On my list of interesting integration projects are a non-CVI interface for ShellNotify (tray icons) and awesome Windows Explorer integration to add a properties sheet and better launch-time functionality for LabVIEW files. This seems like it falls into that kind of category - pretty awesome but questionably useful.
Call Library node calling "LabVIEW"
in LabVIEW General
Posted
I'm curious (and maybe this is becoming OT) why VIs such as that which don't have much/any logic on the BD were just exposed as "native" nodes - no block diagram to even try to look at. Is there are a lot of overhead in nodes like that?