I am only somewhat familiar with multi-threading in that I've read about it but have never used it in practice.
I have a project that uses a third party library that shares the status of an input device by raising events. The problem is, the way the library is written these events are raised from a different thread.
My application does not need to be multi-threaded and I've run into a lot of classic threading issues (UI controls complaining about being interacted with from a different thread, collections that get modified as one piece of code is iterating over it, etc.).
I just want the 3rd party library's event to be given back to my UI thread. Specifically what I think should happen is:
My class receives the event and the handler is being run on a different thread than the UI. I want to detect this condition (like with InvokeRequired), and then perform the equivalent of BeginInvoke to give control back to the UI thread. Then the proper notifications can be sent on up the class hierarchy and all of my data is only touched by the one thread.
The problem is, the class that is receiving these input events is not derived from Control and therefore doesn't have InvokeRequired or BeginInvoke. The reason for this is that I tried to cleanly separate UI and the underlying logic. The class is still being run on the UI thread, it just doesn't have any UI inside the class itself.
Right now I fixed the issue by ruining that separation. I pass in a reference to the control that will be displaying data from my class and using its Invoke methods. That seems like it defeats the whole purpose of separating them because now the underlying class has a direct dependence on my specific UI class.
Perhaps there's a way to save a reference to the thread that ran the constructor and then there's something in the Threading namespace that will perform the Invoke commands?
Is there a way around this? Is my approach completely wrong?
Look into the AsyncOperation
class. You create an instance of AsyncOperation
on the thread you want to call the handler on using the AsyncOperationManager.CreateOperation
method. The argument I use for Create
is usually null, but you can set it to anything. To call a method on that thread, use the AsyncOperation.Post
method.