C#, events, threads and Invoke



  • Good morrow,

    I have to communicate with hardware, said hardware has an unmanaged API dll for which there is an interface written in VB (a standard DLL wrapper) which I have subsequently wrapped slightly more in C#. This wrapped wrapper then gets used to in a class defining the different ways this piece of hardware can be interacted with, and several events that the hardware can throw.

    These events are called as a result of a callback set up in the initial wrapper set up, which means that they are all in their own threads.

    Essentially the situation is thus:

    for each piece of hardware, An object is created, which creates a connection to the hardware and sets one of it's methods as the endpoint for the hardware dll's callback.

    each piece of hardware then essentially has its own thread linked to its own object, but those objects are all created from one initial thread.

    obviously, since the callback is called from the inner thread, the events that are raised from it's handler are also going to be in that thread. meaning that, unchanged, at the top level where my code external to this wrapped wrapper instantiates these objects I need to set up a delegate and invoke stuff in the event handler if I want to reference stuff in the main thread, which obviously exposes a bit too much implementation detail (and adds complexity) to the code calling this API, or at least I think so.

    Is there any way to bring that invoking back inside my API at all? e.g. is there anything I can do in my object's constructor (where I will be in the correct thread) to set up for when the method is called to invoke the event correctly in that thread?

    This may well expose a lack of knowledge of this area, that is because I lack knowledge in this area. I have worked with standard gui triggers event type deals, but never particularly dealt with less standard event processing such as I am describing here. If this makes me appear to be a moron, it's because I have previously stood on the shoulders of sexy giants.


  • FoxDev

    I know it's less than optimal, but when i have an invoke across thread boundaries issue i usually just create a WPF GUI object (a label say) and use the invoke method on it that ensures that whatever i gave it to run runs on the GUI thread.

    of course the reason i use that is almost always to manipulate the states of other WPF GUI objects from a worker thread (progress feedback anyone?) and those calls have to be from the GUI thread.

    I'm sure with a little creative thinking one could create an object that captures the thread it is created on and exposes an invoke method that takes an action, or delegate from any other thread and arranges it to run on the thread that created the object.

    That would probably get complicated fast, but it's the only solution i can think of (because i rarely deal with esoteric event driven models in C#. i should do more with them, but i don't, yet.)



  • this was the kind of thing I was thinking of, but I felt like I would much rather not have to pass anything into my API constructor that seems weird, and a UI object would definitely feel weird. I feel like there should be a way to do this that actually makes sense, because the thread exists and only needs to exist within my API, and I'm sure I wouldn't be the first person to want something like this.


  • FoxDev

    maybe what you are looking for is the C# 4.5 async methods. Those are [expletive deleted] awesome, and what i'd go for if i could use 4.5 and the objects i was dealing with did not have the kind of thread affinity that the WPF objects have.



  • I don't think that works for me, as far as I know async lets me fire something off and pick up the result later, which certainly is really useful, but I can't see how to make that work when I am basically just setting up to listen to events from an external source, over which I have no control, and those events turn up in a different thread.

    I could set up a Label in my constructor I guess, but then I have a load of references to weird assemblies that don't really belong in a windows service (which is what the app is destined to become, but I also tend to implement it in a simple windows forms test harness so I can easily test the inner workings without installing/uninstalling as a service (I am guessing that is pretty standard practice)


  • FoxDev

    ok. so let me see if i follow you on this.

    you have main processing thread A
    A creates object B to handle external API C
    API C periodically fires events that object B picks up and does some processing, maybe
    Object B then has to inform process A that the event occured, likely with some data about the event

    correct?

    in that case, unless you have some weird thread affinity issues that I've never yet run into outside of dealing with GUI, i think what you want to do is create events on object B that process A registers for with the appropriate handlers to do whatever it needs to with the events as they occur.



  • @accalia said:

    API C periodically fires events that object B picks up and does some processing, maybe
    Object B then has to inform process A that the event occured, likely with some data about the event

    correct?


    Not quite, here is the situation as I understand it from reading a little and from the way .NET behaves with threads and events.

    Object B is instantiated in thread A
    Object B registers to receive events in API C.
    API C periodically fires events in thread C, the event handlers in object B then run in thread C.
    object B then does some processing and raises its own events, also in thread C.
    any other objects in A which are listening to events thrown in object B will handle those events in thread C.

    Obviously Invoke is only a thing in a GUI application, which the API isn't destined for at this stage, however, there is no reason it couldn't be destined for one, and while outside of GUI applications everything might work fine, I would much rather code calling this API just didn't need to know any of that detail and it just functioned like any other API that can periodically throw events that don't need any additional thought.


  • FoxDev

    hmm... Maybe what you want is something like this?

    At least that should work if your concern is to get the processing out of thread C and onto thread A where object B lives.



  • that may be the droid I am looking for, I will investigate.


  • FoxDev

    excellent.

    of that isn't what you are looking for here's the Googlefu i used to find that link: c# invoke on another thread

    perhaps another of those links will help if this one didn't



  • building on that question as a basis - it looks like there is only a synchronization context if a form exists, otherwise shit just workstm, if there is a form, then the context will essentially be the main thread of that form (or the main thread of the form the calling code is running in, either way, exactly what I wanted), otherwise it will be null.

    this means I can basically do the equivalent of if(InvokeRequired) with if(synchronizationContext != null) where synchronizationContext was set in my constructor. if true, synchornizationContext.Post() functions almost identically to Invoke.

    good enough for me


  • FoxDev

    excellent!

    glad my googlefu could help.



  • just funished setting this all up, works flawlessly 😃

    its surprising how different results you get for similar terms. I did google for this but along the lines of invoke and events rather than invoke and thread... didnt get anything useful.



  • That dude is a scary motherfucker. I didn't know StackOverflow had enforcers.


  • FoxDev

    yeah. scary.

    i would have disabled the oneboxing, but it was early and i couldn't be arsed to figure out/remember how.


  • Discourse touched me in a no-no place

    Quick! Vote him up and maybe he'll go and enforce on some other person.



  • Not reading the posts just yet,

    I usually approach this with method delegates, but I'm usually calling from a background worker, not a separate piece of hardware. I imagine the concept's the same though.

    OriginalObject.Invoke((MethodInvoker)delegate { OriginalObject.SomeMethod = SomeFunction.Process; });
    ```</strike>
    
    Looks like you got it working, good for you lol
    
    ... Nice, discourse. Show me that strikethrough for literally everything in my post, then proceed to only strike out the first line.
    
    Good for you, discoursistency.


  • @Matches said:

    OriginalObject.Invoke

    the problem there as I found it was Invoke only exists on Control objects, i.e. UI components, of which the original object was not one.

    the context thing I found seems to be essentially what invoke is doing under the hood, or maybe just a similar equivalent, but in any case unless I am wrong this was the only option to ensure compatibility in any setup without really weird references



  • I think you're basically looking for an event dispatcher.

    Something like this?

    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
            network_links.Add(new NetworkLinkVM(link, start_node, end_node));
    

    (If you've already solved, this is probably information you don't need)



  • yeah that would work, although I would wonder what Application.Current.Dispatcher would do differently from SynchronizationContext.Current.Post, but it works so its all good unless something transpires to indicate a massive explosion is going to happen the way I have it now.

    It might be the Dispatcher was introduced in a more recent edition of the language (SynchronizationContext I believe was in .net 2.0) or maybe its just 2 different implementations of the same thing, I am not informed or interested enough to say.


Log in to reply