Jump to content

asbo

Members
  • Posts

    1,256
  • Joined

  • Last visited

  • Days Won

    29

Posts posted by asbo

  1. For the record, the reason that we export functions is so that we can expose VIs that call those functions, so pretty much all of those functions are exposed as VIs already in the palettes. Those that are not exposed as single VIs are part of other VIs. Calling things like MoveBlock directly are particularly dangerous since they arbitrarily overwrite memory.

    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?

  2. 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.

  3. 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.

  4. 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:

    post-13461-0-94904100-1340154576_thumb.p

    post-13461-0-63089700-1340154578_thumb.p

    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?

  5. 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.

  6. 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?

  7. 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:

    post-13461-0-91942100-1340058683_thumb.p

    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.

  8. 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?

  9. 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.

  10. 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.

  11. 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...

  12. 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.

×
×
  • Create New...

Important Information

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