2009-11-05 45 views
1

我需要編寫一個應用程序來遍歷我們的數據庫,並在每條記錄上執行各種分析。爲了做到這一點(部分用於創建插件支持的學習練習),我想使用插件模型。.net中的插件體系結構和處理事件

目前,我在我的主應用程序中有一個簡單的界面,該插件可以實現。然後,我的應用程序將所有DLL加載到一個文件夾中查找實現Interface的文件夾。

正如你在下面的僞代碼中看到的,我必須通過調用處理方法的所有加載插件繼續執行一個循環。

Sub ProcessData() 
    For Each Record In MyDataSet 

     For Each Plugin In MyPluginCollection 
      Plugin.ProcessRecord(Record) 
     Next 

    Next 
End Sub 

如果我想讓每個插件異步啓動,那麼當所有插件完成後我將如何跟蹤?

Sub ProcessData() 
    For Each Record In MyDataSet 

     # Start all the plugins off on their processing task    
     For Each Plugin In MyPluginCollection 
      CreateNewThreadFor Plugin.StartProcess(Record) 
     Next 

     # Do not start the next record until this record is completed by all plugins 
     Dim Complete As Boolean = False 
     While Not Complete 
      For Each Plugin In MyPluginCollection 
       If Plugin.IsBusy Then 
        Complete = False 
       End If 
      Next 
      DoEvents 
     End While 

    Next 
End Sub 

還是我只是打開自己的世界,試圖以這種方式多線程的痛苦?

回答

0

使用手動重置事件可能是另一種:

ForEach plugin 
    Create new thread for plugin 
    Add thread to thread list 
    Start the plugin method execution 
Next 

ForEach Thread in thread list 
    Thread.Join() //blocking call until Thread is completed 

通過匿名和擴展方法這可以用非常少的線來實現的。這裏是C#中的一個例子(未經測試):

List<Thread> lstThreads = new List<Thread>(); 
Thread objThread; 

foreach(Record r in MyDataSet) 
{ 
    lstThreads.Clear(); 
    MyPluginCollection.ForEach(delegate(Plugin p) 
    { 
     objThread = new Thread(new ThreadStart(delegate() 
     { 
      p.StartProcess(Record); 
     })); 
     lstThreads.Add(objThread); 
    }); 
    lstThreads.ForEach(t => t.Start()); 
    lstThreads.ForEach(t => t.Join()); 
} 
+0

嗯,這似乎很整齊。我會在設置Events方法之前首先嚐試這一個。 – Cylindric 2009-11-05 17:03:50

0

您想閱讀ManualResetEvents。他們會做的。 http://www.codeproject.com/KB/threads/AutoManualResetEvents.aspx

這並不是說你沒有進入痛苦的世界,但是。

這裏是一個例子。粘貼到一個命令行應用程序

var r = new Random(); 
Action a =() => Thread.Sleep(r.Next(5000)); 

Action<int> process = i => //represents your plugin 
{ 
    Console.WriteLine("Thread " + i + " started"); 
    Thread.Sleep(r.Next(5000)); 
    Console.WriteLine("Thread " + i + " finished"); 
}; 

var mres = new List<ManualResetEvent>(); 
for (var i = 0; i < 10; i++) 
{ 
    var count = i; 
    var mre = new ManualResetEvent(false); 
    new Thread(() => 
        { 
         process(count); 
         mre.Set(); 
        }).Start(); 
    mres.Add(mre); 
} 
ManualResetEvent.WaitAll(mres.ToArray()); //try commenting this line 
Console.WriteLine("All threads finished. Press enter to continue"); 
Console.ReadLine(); 
+0

我不是很熟悉C#語法,但在您的示例中,您創建了一個由進程調用和mre.set組成的新線程。我只使用過AddressOf啓動線程的方式。 如何讓mre.set啓動? – Cylindric 2009-11-05 15:16:20

+0

我是否正確地認爲mre.Set()必須與「工作」在同一個線程上發生,以便在工作完成時MRE清除? – Cylindric 2009-11-05 15:21:21

+0

是的,如果你在主線程上執行它,它會過早設置。 – mcintyre321 2009-11-05 16:30:20

0

最好的辦法是與事件「ProcessCompleted」,而事件中檢查你的擴展接口,如果每個插件都準備好指標(如帶有屬性「ProcessInProgress」)。

鮑比