2012-05-17 155 views
5

我在.Net 3.5中有一個多線程的Windows服務,並且在創建多個線程時我有一些麻煩來正確地停止該服務。停止多線程的Windows服務

此服務用於創建只有一個線程來完成所有的工作,我只是將其更改爲多線程。它完美地工作,但是當服務停止時,如果多個線程正在執行,它將掛起服務,直到所有線程完成。

當該服務啓動後,我創建了一個後臺線程來處理的主要過程:

protected override void OnStart(string[] args) 
    { 
     try 
     { 
      //Global variable that is checked by threads to learn if service was stopped 
      DeliveryConstant.StopService = false; 
      bool SetMaxThreadsResult = ThreadPool.SetMaxThreads(10, 10); 

      ThreadStart st = new ThreadStart(StartThreadPool); 
      workerThread = new Thread(st); 
      workerThread.IsBackground = true; 
      serviceStarted = true; 
      workerThread.Start(); 
     } 
     catch (Exception ex) 
     { 
      //Log something; 
     } 

這裏是StartThreadPool方法:

//Tried with and without this attribute with no success... 
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] 
    public void StartThreadPool() 
    { 
     while (serviceStarted) 
     { 
      ProcessInfo input = new ProcessInfo(); 

      try 
      { 
       int? NumPendingRequests = GetItems(50, (Guid?)input.ProcessID); 

       if (NumPendingRequests > 0) 
       { 
        input.ProcessType = 1; 
        input.ProcessID = Guid.NewGuid(); 
        ThreadPool.QueueUserWorkItem(new WaitCallback(new DispatchManager().ProcessRequestList), input); 
       } 
      } 
      catch (Exception ex) 
      { 
       //Some Logging here 
      } 
     } 

     DeliveryConstant.StopService = true; 
    } 

我在單獨的類中創建一個靜態變量通知線程服務已停止。當此變量的值爲true,所有線程應該停止主循環(每個循環):

 public static bool StopService; 

最後,調用OnStop方法:

protected override void OnStop() 
    { 
     DeliveryConstant.StopService = true; 

     //flag to tell the worker process to stop 
     serviceStarted = false; 

     workerThread.Join(TimeSpan.FromSeconds(30)); 
    } 

在ProcessRequestList方法中,在每個foreach的結尾,我檢查StopService變量的值。如果這是真的,我打破循環。

這裏的問題是: 的線程中的50項塊創建。當我在數據庫中有50個或更少的項目時,只創建一個線程,並且一切都很好。 當我有超過50個項目時,將創建多個線程,並且當我嘗試停止服務時,它不會停止,直到完成所有後臺線程。

從日誌中,我可以看到方法OnStop只在所有線程完成後執行。

任何線索可以改變什麼來解決這個問題?

+0

嘗試在while循環中放置睡眠(50)。 –

+0

在我看來,你沒有包含代碼的最重要部分。這是ProcessRequestList方法的實現。 –

+0

你可以顯示StopService被詢問的代碼嗎?查看使用CancellationToken通過靜態var,因爲它是爲這樣的事情。 – hatchet

回答

9

blog answer指出調用OnStop不叫,直到所有的線程池任務完成,這是新聞,但我會解釋您的問題。

我已經派出許多多線程Windows服務,但我更喜歡創建自己的後臺線程,而不是使用線程池,因爲這些都是長期運行的線程。我實例化工作者類並在線程上啓動他們的DoWork()方法。我也更喜歡使用回調來啓動類來檢查停止信號並傳遞狀態,而不是僅僅測試一個全局變量。

+0

你確切地指出了這個問題。非常感謝!這幾乎是我說的那樣,但不知道這是一種預期的行爲。知道這一點,我現在正在檢查工作線程中的服務狀態,並且它像魅力一樣工作。不確定(但)它的性能會有多高。謝謝! – Roberto

+0

Roberto,你是否介意在你的問題中發佈你的解決方案,或者是什麼布爾StopService變量? – PAULDAWG

3

你缺少內存屏障各地訪問StopService,如果你有多個CPU,這可能是一個問題。更好地鎖定所有訪問共享變量的引用對象。例如:

object @lock; 

... 

lock (@lock) 
{ 
    StopService = true; 
} 

編輯:作爲另一個答案已經揭曉,這個問題沒有鎖定問題,但我在這裏離開這個答案的事情檢查與多線程的同步方案。

使共享變量的波動會在很多情況下工作的很好,但它是比較複雜的,以證明正確的,因爲它不排放全柵欄。

+0

這不是關於原子性,而是關於記憶障礙。原子性意味着另一個線程將會看到所有的線程 - 或者沒有線程。內存屏障(這裏有兩種類型,但爲簡單起見,我們略過)確保「沒有」情況不會發生。 –

+0

它被標記爲c#,而不是java – hatchet

+0

糟糕。我在兩個問題之間跳躍。在這裏回到那個misedit。 –