2012-02-13 63 views
1

我有一個VB .Net服務,它使用System.Threading而不是定時器來基本上做一個定時器應該做的事情。我的問題是在線程處於睡眠狀態時停止服務。請參見下面的代碼:服務啓動VB .Net服務在線程休眠時不會停止

如果例如1分鐘後
Imports System.Threading 

Public Class AService 
    Private stopping As Boolean 
    Private stoppedEvent As ManualResetEvent 

    Public Sub New() 
     InitializeComponent() 
     Me.stopping = False 
     Me.stoppedEvent = New ManualResetEvent(False) 
    End Sub 

    Protected Overrides Sub OnStart(ByVal args() As String) 
     ' Add code here to start your service. This method should set things 
     ' in motion so your service can do its work. 
    End Sub 

    Protected Overrides Sub OnStop() 
     ' Add code here to perform any tear-down necessary to stop your service. 
     Me.stopping = True 
     Me.stoppedEvent.WaitOne() 
    End Sub 

    Private Sub ServiceWorkerThread(ByVal state As Object) 
     ' Periodically check if the service is stopping. 
     Do While Not Me.stopping 
      ' Perform main service function here... 
      ' do anything here and wait 15 minutes before doing it again 
      Thread.Sleep(15 * 60000) ' Sleep for interval 
     Loop 

     ' Signal the stopped event. 
     Me.stoppedEvent.Set() 
    End Sub 
End Class 

,就不能停止,直到它每隔15分鐘蜱和線程被喚醒。有什麼方法可以捕捉服務試圖停止的信號,並中斷線程?

回答

1

這是我使用的代碼。在睡覺或表演時停止沒有問題。

Class MyService 
    Inherits ServiceBase 

    Private Shared ReadOnly SleepPeriod As New TimeSpan(0, 15, 0) 
    Private Shared ReadOnly StopTimeout As New TimeSpan(0, 3, 0) 
    Private _TerminationHandle As New ManualResetEvent(False) 
    Private _IsRunning As Boolean = False 
    Private _ServiceThread As New Thread(Addressof ServiceMain) 

    Protected Overrides Sub OnStart(args As String()) 
     _TerminationHandle.Reset() 
     _IsRunning = True 
     _ServiceThread.Start() 
    End Sub 

    Protected Overrides Sub OnStop() 
     _TerminationHandle.Set() 
     _IsRunning = False 
     ' Terminate the thread if it doesn't stop within 3 minutes of request. 
     If Not _ServiceThread.Join(StopTimeout) Then _ServiceThread.Abort() 
     _TerminationHandle.Close() ' Can use .Dispose() if using .Net 4.0 or later. 
    End Sub 

    Private Sub ServiceMain() 
     Do 
      ' TODO: Do work here. Watch for "_IsRunning = False" to abort working when stopping. 

      ' Sleep for 15 minutes at a time. Terminate when service is stopping. 
     Loop While _IsRunning AndAlso TerminationHandle.WaitOne(SleepPeriod) 
     ' TODO: Clean up. 
    End Sub 
End Class 
+0

由於其保護級別,_TerminationHandle.Dispose()不可訪問。有任何想法嗎?這是完美的解決方案 – 2012-02-14 15:55:37

+0

我正在使用.Net 3.5,切換到4.0,現在它的工作。我必須做一些測試,但是謝謝,這是一個很好的代碼庫 – 2012-02-14 16:06:21

+0

啊,我不知道這是最近的一次增加。你可以在早期版本的.Net中使用'.Close()'。我在答案中做了一個筆記。謝謝! – 2012-02-14 21:58:43

1

在您當前的型號中,沒有。您只使用單個線程,並且您的代碼在15分鐘內顯式「暫停」該線程,因此在此期間任何事件都沒有響應。但是,如果您對此採取稍微改進的方法,則可以改進:在不同線程中運行您的ServiceWorkerThread,然後您的主線程可以保持對外部事件的響應。當「停止」信號到達時,如果需要,您可以強制中止工作線程。

+0

約是怎麼回事很好的解釋,給這個使用http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx – Gent 2012-02-14 22:18:27

0

看看在Thread.Interrupt方法:http://msdn.microsoft.com/en-us/library/system.threading.thread.interrupt.aspx#Y0

然而,這需要你有機會到正在運行的的Thread實例「的服務。」如果這是主線程,那麼這是一個不行,但如果它是一個產生的線程,那麼你可以調用中斷,它會中斷處於休眠/阻塞狀態的Thread

+0

一試這是主線程 – 2012-02-13 21:26:07

+0

如果您不能將代碼移動到單獨的線程中,那麼除了執行一些反模式忙碌等待外,沒有辦法繞過它。您可以通過實施類似於rerun的解決方案來最大限度地減少關閉「滯後」,並將睡眠時間設置爲更可接受的(幾秒鐘或更多沿着這些線)。 – Kiril 2012-02-13 21:31:03