2014-02-07 41 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)); 
}