2012-07-26 54 views
0

我有電子郵件發送窗口服務的問題。該服務在每三分鐘延遲一次後開始,並獲取要從數據庫發送的消息,並開始發送它。這是怎樣的代碼看起來像:C#線程在窗口服務創建問題

 MessageFilesHandler MFHObj = new MessageFilesHandler(); 
     List<Broadcostmsg> imidiateMsgs = Manager.GetImidiateBroadCastMsgs(conString); 
     if (imidiateMsgs.Count > 0) 
     { 

      // WriteToFileImi(strLog); 

      Thread imMsgThread = new Thread(new    ParameterizedThreadStart(MFHObj.SendImidiatBroadcast));    
      imMsgThread.IsBackground = true; 
      imMsgThread.Start(imidiateMsgs); 
     } 

這將消息發送到大名單,並且需要很長時間才能完成發送到一個更大的列表。現在問題發生在消息仍在發送並且服務獲得新消息發送時,之前的發送受到侮辱並且新的消息發送開始,儘管我正在使用線程,每次服務獲取消息發送它時都會啓動一個新線程。 可以請你幫忙,我在代碼中犯的錯誤。

+1

它看起來像你有一個線程使用'imidiateMsgs',但你沒有任何類型的線程安全鎖定保護'imidiateMsgs'。如果你有一本關於C#的好書,它應該有一個關於線程安全的章節,你可以學習。 – Tod 2012-07-26 05:27:19

+0

感謝您的建議。我一定會關注,但現在我沒有時間閱讀一本書。我需要儘快解決這個問題。如果你有解決方案,請幫助我。謝謝 – 2012-07-26 05:31:19

回答

0

它看起來像要求是建立一個消費者生產者隊列。在哪個製作人會不斷添加消息到列表中,並且消費者將從該列表中選擇項目並且使用它來執行一些工作 唯一讓我擔心的是,您每次都創建一個新線程來發送電子郵件,而不是從線程池中選擇線程。如果繼續創建越來越多的線程,應用程序的性能會因上下文切換所產生的頭部而降低。

如果您使用.net framwe工作4.0,那麼靈魂變得相當容易。您可以使用System.Collections.Concurrent.ConcurrentQueue進行排隊和出列您的項目。它的線程安全,所以不需要鎖定對象。使用Tasks來處理您的消息。

BlockingCollection在其構造函數中需要一個IProducerConsumerCollection,或者如果調用它的空構造函數,它將默認使用ConcurrentQueue。

這樣才能排隊消息。

//define a blocking collectiom 
var blockingCollection = new BlockingCollection<string>(); 

//Producer 
Task.Factory.StartNew(() => 
{ 
    while (true) 
    { 
     blockingCollection.Add("value" + count); 
     count++;      
    } 
}); 

//consumer 
//GetConsumingEnumerable would wait until it find some item for work 
// its similar to while(true) loop that we put inside consumer queue 
Task.Factory.StartNew(() => 
{ 
    foreach (string value in blockingCollection.GetConsumingEnumerable()) 
    { 
     Console.WriteLine("Worker 1: " + value); 
    }     
}); 

UPDATE

由於您使用的框架3.5。我建議你看看Joseph Albahari的實施Consumer/Producer Queue。它是你找到的最好的之一。

直接從上面的鏈接

public class PCQueue 
{ 
    readonly object _locker = new object(); 
    Thread[] _workers; 
    Queue<Action> _itemQ = new Queue<Action>(); 

    public PCQueue (int workerCount) 
    { 
    _workers = new Thread [workerCount]; 

    // Create and start a separate thread for each worker 
    for (int i = 0; i < workerCount; i++) 
     (_workers [i] = new Thread (Consume)).Start(); 
    } 

    public void Shutdown (bool waitForWorkers) 
    { 
    // Enqueue one null item per worker to make each exit. 
    foreach (Thread worker in _workers) 
     EnqueueItem (null); 

    // Wait for workers to finish 
    if (waitForWorkers) 
     foreach (Thread worker in _workers) 
     worker.Join(); 
    } 

    public void EnqueueItem (Action item) 
    { 
    lock (_locker) 
    { 
     _itemQ.Enqueue (item);   // We must pulse because we're 
     Monitor.Pulse (_locker);   // changing a blocking condition. 
    } 
    } 

    void Consume() 
    { 
    while (true)      // Keep consuming until 
    {         // told otherwise. 
     Action item; 
     lock (_locker) 
     { 
     while (_itemQ.Count == 0) Monitor.Wait (_locker); 
     item = _itemQ.Dequeue(); 
     } 
     if (item == null) return;   // This signals our exit. 
     item();       // Execute item. 
    } 
    } 
} 

優點這種方法以代碼是你可以控制你需要創建爲優化性能的線程數。使用線程池方式,儘管它很安全,但您無法控制可同時創建的線程數。

+0

任務體內的無限循環?哦,沒有... – Dennis 2012-07-26 06:05:42

+0

如果它沒有無限循環,你將如何確保你的消費者線程總是處理。事件可以用來表示新項目的到來,但我還沒有看到任何生產者,消費者隊列與事件發信號 – Anand 2012-07-26 06:13:58

+0

我正在使用框架3.5 – 2012-07-26 07:18:14

0

我覺得你在一個循環裏面使用你的代碼WAITS對於新的消息,你是否管理過這些等待?讓我們來看看:

while(imidiateMsgs.Count == 0) 
{ 
    //Wait for new Message 
} 

//Now you have a new message Here 

//Make a new thread to process message 

還有對於等待中不同的方法,我建議使用BlockingQueues:

在公共場所:

BlockingCollection<Broadcostmsg> imidiateMsgs = new BlockingCollection<Broadcostmsg>(); 

在你的消費者(線程產生消息):

SendImidiatBroadcast = imidiateMsgs.Take();//this will wait for new message 
//Now you have a new message Here 

//Make a new thread to process message 

在生產者(回答消息的線程):

imidiateMsgs.Add(SendImidiatBroadcast); 

而且你必須使用線程池,每次回答的消息作出新的線程,不要每次初始化新的線程。