2011-05-20 72 views
6

我想寫一個WCF Servce,它將駐留在Windows服務中。此WCF服務將只添加字符串到列表中,然後工作線程將定期處理此列表。達到此目的的最佳方法是什麼?我讀過沖突的例子,這讓我感到困惑。服務和線程共享列表對象的最佳方式是什麼?工作線程的WCF服務?

更新: 感謝您的回覆。只是爲了澄清,我並沒有爲列表的同步或如何使其線程安全而苦苦掙扎。這一切似乎與我在C++中習慣的相同。我正在努力的是在哪裏定義此列表,以便可以從WCF服務和工作線程訪問它。在C++中,我會在全局範圍創建列表,但C#沒有全局範圍。如果我在WCF服務類中定義它,線程就看不到它。如果我在服務類中定義它(線程函數定義和啓動的地方),那麼WCF服務將無法看到它。我確信我前段時間在ATL做了類似的事情,但是這是星期五下午,灰色細胞已經放棄了這一天。

Update2: 我應該在哪裏定義工作線程?在Windows服務類(即主機)中還是在WCF服務中? WCF服務應該是一個具有列表成員和線程功能的單例服務嗎?這解決了訪問問題。在完成了大量的COM之後,我將WCF服務視爲一個COM組件,並在實例被訪問後死去。這導致我想要將靜態列表和線程函數放在Windows服務類中。這仍然感覺它是更自然的地方,但也許我只是沒有以.NET的方式思考。

回答

3

1)創建Windows服務

2)主機WCF在WS(http://msdn.microsoft.com/en-us/library/ms731758.aspx

3)讓一個線程同步(http://www.albahari.com/threading/part2.aspx

4)利潤!

+0

謝謝。第一部分非常有用。第二部分,我對C++時代的線程同步已經有了很好的理解,因爲它根本就沒什麼不同。我更多問的是如何獲得可供WCF服務對象和工作線程訪問的列表?在C++中,我只是在全局範圍創建列表(並使其像Crtical部分一樣安全),但C#沒有全局範圍的概念。 – Jonnster 2011-05-20 15:00:15

+0

您必須在Windows服務應用程序內託管wcf。它將有一個應用程序範圍。雖然看看一些面向對象的設計模式,讓它變得乾淨而舒適 – Turowicz 2011-05-21 09:21:30

+0

你介意擴展你的最新評論。我無法弄清楚它有一個應用程序範圍。也許我正在看錯誤的例子。 – Jonnster 2011-06-02 16:23:44

1

一般模式是在啓動服務時啓動服務主機。一旦開始,您可以創建您的工作線程。工作者線程和服務調用將需要訪問需要同步的共享數據結構。將共享數據對象上的服務存款項目發送給Wait handle以運行工作線程。一旦工人完成重置等待句柄的狀態。

+0

啊,這是我在那裏掙扎的地方。我認爲Windows服務是WCF服務主機。它不是那樣工作嗎?我對.NET很陌生(特別是WCF) – Jonnster 2011-05-20 14:45:16

2

這是一個使用.NET 4中的併發集合的快速小外殼(對於這個問題,我也用這個例子來說明.NET 4中的任務並行庫)。您的問題聲明似乎是在不同的線程或進程經典的生產者/消費者,所以這應該給你如何構建事情像樣的想法:

namespace ConcurrentCollectionTest 
{ 
    using System; 
    using System.Collections.Concurrent; 
    using System.Threading.Tasks; 

    internal static class Program 
    { 
     private static void Main(string[] args) 
     { 
      ConcurrentQueue<string> cq = new ConcurrentQueue<string>(); 
      BlockingCollection<string> bc = new BlockingCollection<string>(cq); 
      bool moreItemsToAdd = true; 

      // Consumer thread 
      Task.Factory.StartNew(() => 
      { 
       while (!bc.IsCompleted) 
       { 
        string s = bc.Take(); 

        Console.WriteLine(s); 
       } 
      }); 

      // Producer thread 
      Task.Factory.StartNew(() => 
      { 
       int i = 1; 

       while (moreItemsToAdd) 
       { 
        bc.Add("string " + i++); 
       } 

       bc.CompleteAdding(); 
      }); 

      // Main Thread 
      Console.ReadLine(); 
      moreItemsToAdd = false; 
      Console.ReadLine(); 
     } 
    } 
} 
+0

謝謝你的嘗試,但沒有解釋發生了什麼,它並不意味着太多。我沒有看到我會在Windows服務中放置該代碼來解決問題。感謝您的輸入。 – Jonnster 2011-05-20 15:08:49

1

我想你問的是具體如何做您將集合實例的引用傳遞給WCF服務實例。問題的癥結在於:通常,ServiceHost代碼將根據服務的InstanceContextMode設置啓動WCF服務實例(默認值爲PerSession)。這意味着它將按需要爲每個客戶端會話創建一個實例。由於您的主機代碼無法直接訪問這些自動創建的實例,因此您無法注入共享集合。

一種解決方案是爲您的主機提供WCF服務實例,通過構造函數參數或屬性設置器添加共享集合。有一個ServiceHost的構造函數需要這個實例,但它有很大的折衷。這種方法意味着您正在創建單身WCF服務(InstanceContextMode = Single),因此可擴展性將受到影響。您可以通過將ConcurrencyMode設置爲多個來緩解這種情況,但是您還必須編寫WCF服務代碼來處理資源的內部同步。

+0

謝謝。我剛剛讀過單身人士WCF服務,並剛剛更新了我的原始帖子與這個問題。我對可擴展性權衡感到滿意,因爲它不應該成爲一個問題。如果僅僅是爲了將來參考,我仍然對如何解決這個問題感興趣。我很高興讓它成爲多種併發模式,因爲我很喜歡這種線程同步。謝謝。 – Jonnster 2011-05-20 15:29:45

0

。在C++中,我會在全局範圍創建列表,但C#沒有全局範圍。

任何公共靜態成員都是全局可見的。當然,你必須實現你自己的同步。

1

您可以在WCF服務的靜態構造函數中啓動工作線程。當然,不管ConcurrencyModeInstanceContextMode只有一個工作線程。如果這是你想要的,那麼下面的代碼可能適合你。

[ServiceContract] 
public interface IYourService 
{ 
    [OperationContract] 
    void QueueStringValue(string value); 
} 

[ServiceBehavior(...)] 
public class YourService : IYourService 
{ 
    private static BlockingCollection<string> s_Queue = new BlockingCollection<string>(); 

    static YourService() 
    { 
    var thread = new Thread(
    () => 
     { 
     while (true) 
     { 
      string value = s_Queue.Take(); 
      // Process the string here. 
     } 
     }); 
    thread.IsBackground = true; 
    thread.Start(); 
    } 

    public void QueueStringValue(string value) 
    { 
    s_Queue.Add(value); 
    } 
} 

我已經使用生產者 - 消費者模式來實現工作者線程邏輯。類提供了一種實現該模式的簡單機制。