Sending Events to a specific Thread
开发者_JAVA技巧I have a situation in which I want a thread to process some sequential logic. This thread would need to interact with the main thread on occasion in order to update user input. But it should continue running otherwise without bothering the main thread. I am hopping to do this in an event-driven manner, so that the main thread doesn't have to pole the other thread for interrupts. What is the best way to do this? Is there an event-driven technique to communicating between threads much like there is in MFC?
I am using Visual Studio 2008 and (obviously) the .Net 3.5 framework.
Use the BackgroundWorker
component.
Here you can find the best and complete tutorial about threading in C#, with code samples and examples.
AutoResetEvent and ManualResetEvent might be what you are after. Basically your main thread would wait using the various Wait methods of these classes until you signal from your other thread using the Set method. Then your wating thread will resume and continue with whatever comes afer Wait. This is as good as it gets for an event-style. You have to wait and listen to receive an react on an event. How else are you supposed to stop your thread work in case you get an event gracefully? This is not possible with threads in general in any language.
Your only other possibility is frequent interrupting and polling.
Have a look at .Net Reactive Extensions IObservable and in particular the SubscribeOn and ObserveOn extension methods.
ObserveOn is where the work is done ( your background thread ), SubscribeOn is where the notifications go ( your UI thread ).
If you are using the BackgroundWorker you can raise a Progress event.
Here's an example on how to update a progress bar.
Ah ha! there is an event-driven way to do it. I borrowed the Dispatcher
from WPF. I just give the spinning thread access to the main thread's CurrentDispatcher
I let the thread spin and when it needs attention it invokes a delegate on the Dispatcher
and sleeps waiting for the main thread to interrupt it. I know I could use Invoke
instead of BeginInvoke
, but I needed to use the interrupt because the method that restarts the worker thread is not a synchronous part of the dispatched delegates stack.
For better or worse, here is my code:
private void Run()
{
while (true)
{
...
// Need attention from the main thread
// "_main" is the main thread's Dispatcher instance.
_main.BeginInvoke(new MyEventHandler(OnNeedsAttention), this, new MyEventArgs(...));
try
{
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException) { }
}
}
精彩评论