2014-02-07 33 views
1

我开发了多线程应用程序,用于在线程中完成事件处理。当UI线程中引发的事件创建一个执行业务逻辑并终止的线程时。但是,如果工作线程中的业务逻辑代码导致另一个事件;线程在主UI线程上调用控件并在执行时移动。同时,UI线程为新事件处理创建新线程。这两个线程都以并行方式执行。多线程c#winforms中的事件处理

我想要的是,如果线程导致一个新的事件;等待新的事件完成并继续他们的任务。事件应按顺序处理。

我的任务实际上是大框架的一部分。简而言之,应用程序通过使用反射API将控制事件绑定到目标代码。

以下UI线程处理代码捕获事件时。

Thread workerThread = new Thread(() => executeCommandTargetAsync(..some parameters..)); 
workerThread.Start(); 

工作线程使用控件的InvokeRequired标志,并调用方法与UI线程进行通信。 处理其他线程中的事件而不是UI的目的线程防止由于长时间事件操作(如从数据库更改组合框的数据源)而冻结UI。

+1

你能给出一些简单的示例代码来演示你的问题吗?后台线程如何创建这些事件?通过更改/与UI控件进行交互? – sloth

+1

如果您开始希望等待动作完成并按顺序执行操作,则最好切换到调用方法(如果您不想要具体的依赖关系,则在接口上)。 –

回答

1

尝试使用类“的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(); 
1

运行在主UI线程下面将是灾难性的,因为用户界面将被冻结,反应迟钝。

AutoResetEvent resetEvent = new AutoResetEvent(false); 
resetEvent.WaitOne(); 

相反,你可以使用信号和计时器。 在您的WinForms应用程序创建事件参数或其他合适的包装材料的队列来捕捉引发的事件的essense和包排队和离队的线程同步化的锁

在您创建引发事件,而不是单独的线程排队的数据或信号进入队列。

在你的winodws表单应用程序中有一个计时器,用于轮询队列中的任何新事件并相应地处理这些事件。

如果您使用,则下面的示例代码: 1)当一个事件是由控制的一个凸起只需调用,而不是在你的新主题开始一个新的线程 2)EnqueueEvent所有你要做的就是调用EnqueueEvent与一个新的信号,而不是引发一个事件。 当然,将MyEventSignal类替换为更适合您场景的类,并将计时器代码置于实际的定时器处理程序中。

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)); 
}