Я работаю над службой Windows, с которой это имеет некоторые проблемы Thread.Sleep()
таким образом, я полагал, что попытаюсь использовать таймер вместо этого, как этот вопрос рекомендует:
Использование потока. Сон () в службе Windows
Вещь, мне не совсем ясно, как можно было бы реализовать это. Я полагаю, что это - путь, но я просто хотел удостовериться:
'' Inside The Service Object
Dim closingGate As System.Threading.AutoResetEvent
Protected Overrides Sub OnStart(ByVal args() As String)
Dim worker As New Threading.Thread(AddressOf Work)
worker.Start()
End Sub
Protected Sub Work()
Dim Program = New MyProgram()
closingGate = New System.Threading.AutoResetEvent(False)
Program.RunService(closingGate)
End Sub
Protected Overrides Sub OnStop()
closingGate.Set()
End Sub
'' Inside My Programs Code:
Public Sub RunService(closingGate As AutoResetEvent)
Dim tmr As New Timer
'' ...and so on
closingGate.WaitOne()
End Sub
Кроме использования VB.Net (Ребячество, но я использовал бы C#, если я мог.) я на правильном пути здесь? Это лучше, чем использование Thread.Sleep()
?
Честно говоря, я должен сказать, что, по-моему, вы немного сбились с пути.
Во-первых, в приведенном коде нет никакого смысла; рабочий поток ожидает сигнала, но без причины - он не находится в каком-либо цикле и не ожидает ресурса. Во-вторых, если вам нужно выполнить некоторый (возможно, опущенный) код очистки в рабочем потоке после получения сигнала выключения, ваш сервис может не дать рабочему потоку достаточно времени для очистки.
Но, что более принципиально, все, что вы сделали, это переместили проблему в отдельный поток. Это может сохранить отзывчивость сервиса к контроллеру сервиса, но не устраняет проблему проектирования - и добавляет много ненужной сложности за счет использования потоков и мьютексов; в конечном счете, это только усложнит отладку вашего сервиса, если вам это когда-нибудь понадобится.
Допустим, вам нужно выполнять некоторый код каждые 5 секунд. Идея заключается в том, что вместо того, чтобы "ждать" 5 секунд, вы инвертируете управление и позволяете таймеру вызывать вашу работу.
Это плохо:
protected override void OnStart(string[] args)
{
while (true)
{
RunScheduledTasks(); // This is your "work"
Thread.Sleep(5000);
}
}
Это хорошо:
public class MyService : ServiceBase
{
private Timer workTimer; // System.Threading.Timer
protected override void OnStart(string[] args)
{
workTimer = new Timer(new TimerCallback(DoWork), null, 5000, 5000);
base.OnStart(args);
}
protected override void OnStop()
{
workTimer.Dispose();
base.OnStop();
}
private void DoWork(object state)
{
RunScheduledTasks(); // Do some work
}
}
Вот и все. Это все, что вам нужно сделать, чтобы выполнять работу через регулярные промежутки времени. До тех пор, пока сама работа не будет выполняться несколько секунд подряд, ваш сервис будет оставаться отзывчивым к контроллеру сервиса. Вы даже можете поддерживать паузу при таком сценарии:
protected override void OnPause()
{
workTimer.Change(Timeout.Infinite, Timeout.Infinite);
base.OnPause();
}
protected override void OnContinue()
{
workTimer.Change(0, 5000);
base.OnContinue();
}
Единственный случай, когда вам нужно начать создавать рабочие потоки в вашей службе, - это когда сама работа может выполняться очень долго и вам нужна возможность отменить ее в середине. Это, как правило, требует значительных усилий по проектированию, поэтому я не буду в это вдаваться, не убедившись, что это относится к вашему сценарию.
Лучше не начинать внедрять многопоточную семантику в свой сервис, если вам это действительно не нужно. Если вы просто пытаетесь запланировать выполнение небольших по размеру единиц работы, вам это точно не нужно.
Недавно я написал службу, которая должна была выполнить некоторую работу, затем подождать n минут, а затем зациклиться.
Я также использовал ManualResetEvent (называемый _evt) и вызов Set () в OnStop. Но мне не нужен был таймер.
В служебном потоке у меня было:
for (;;) {
// do some work
if (_evt.WaitOne(_waitInterval)) {
// got the signal => time to leave
break;
}
}
Итак, либо истекло время ожидания => время для дополнительной работы. Или вызывается Set (), и цикл завершается.