Reputation: 111
I develop multi-thread application that event handling done in threads. When event raises in UI thread creates a thread that executes business logic and terminates. However, if business logic code in worker thread causes another event; thread Invokes control on main UI thread and moves on its execution. At the same time, UI thread creates new thread for new event handling. Both these thread executes in a parallel way.
What I want is that if thread causes a new event; wait for new event completition and moves on their task. Events should be handled in order.
My task is actually a part of large framework. Briefly application binds control events to target codes by using reflection api.
UI Thread process code below When event is captured.
Thread workerThread = new Thread(() => executeCommandTargetAsync( ..some parameters.. ));
workerThread.Start();
Worker thread communicates with UI Thread by using Control's InvokeRequired flag and Invoke Method. Purpose of handling of events in other threads instead of UI Thread prevent to freeze UI because of long event operation such as changing datasource of combo box from database.
Upvotes: 1
Views: 1364
Reputation: 505
Running the following in your main UI thread would be disastrous because the UI will be frozen and unresponsive.
AutoResetEvent resetEvent = new AutoResetEvent(false);
resetEvent.WaitOne();
Instead you could use signals and a timer. In your winforms application create a queue of event args or other suitable wrapper to capture the essense of the raised events and wrap queuing and dequeuing in thread syncronization locks
In the separate threads that you are creating instead of raising events enqueue the data or signal into the queue.
In your winodws forms application have a timer that polls the queue for any new events and deal with those accordingly.
If you used the following sample code then: 1) When an event is raised by one of the controls simply call EnqueueEvent instead of starting a new thread 2) in your new threads all you would do is call EnqueueEvent with a new signal instead of raising an event. Of course replace MyEventSignal class with something more appropriate to your scenario and place the timer code in an actual timer handler.
public class MyEventSignal
{
public MyEventSignal()
{
}
public MyEventSignal(object _Sender, EventArgs _Args)
{
Sender = _Sender;
Args = _Args;
}
object Sender { get; set; }
EventArgs Args { get; set; }
}
private static object syncRoot = new object();
private static Queue<MyEventSignal> eventSignalQueue = new Queue<MyEventSignal>();
public static void EnqueueEvent(MyEventSignal NewEventSignal)
{
lock (syncRoot)
{
eventSignalQueue.Enqueue(NewEventSignal);
}
}
private static MyEventSignal DequeueEvent()
{
MyEventSignal result;
result = null;
lock (syncRoot)
{
if (eventSignalQueue.Count > 0)
{
result = eventSignalQueue.Dequeue();
}
}
return result;
}
private void TimerUI_Tick(object sender, EventArgs e)
{
MyEventSignal newSignal;
newSignal = DequeueEvent();
while (newSignal != null)
{
// start new thread to do stuff based on event signal
newSignal = DequeueEvent();
}
}
private void DoStuffOnParalleThread()
{
System.Threading.ThreadStart MyThreadStart;
System.Threading.Thread MyThread;
MyThreadStart = new System.Threading.ThreadStart(WorkerThreadRoutine);
MyThread = new System.Threading.Thread(MyThreadStart);
MyThread.Start()
}
private void WorkerThreadRoutine()
{
// Do stuff
//Instead of raising an event do this of course specify your event args
// or change the MyEventSignal class to suit
Form1.EnqueueEvent(new WinApp.Form1.MyEventSignal(this, EventArgs.Empty));
}
Upvotes: 1
Reputation: 2857
try to use the class "AutoResetEvent" :
AutoResetEvent resetEvent = new AutoResetEvent(false);
resetEvent.WaitOne();
//pass the resetEvent object to thread 2, and when you want to continue processing the thread 1 you use the method resetEvent.Set();
Upvotes: 1