具有多个desiredStatus的ServiceController.WaitForStatus

时间:2016-07-14 15:11:38

标签: c# service windows-services

我目前使用以下内容等待服务启动...

srvCtl.Start();
srvCtl.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 30))

如果某个服务在启动后立即停止,我也想说明它被停止了。

有没有办法等待ServiceControllerStatus.RunningServiceControllerStatus.Stopped

3 个答案:

答案 0 :(得分:1)

以下可能有点问题,因为任务和线程彼此不太喜欢,但你可以这样做:

CancellationTokenSource cts = new CancellationTokeSource();

List<Task> tasks = new List<Task>
{
    Task.Run(()= > srvCtl.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 30)), cts),
    Task.Run(()= > srvCtl.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 30)), cts),
    ...
}

// When any of the tasks completes, it means the service reached on of the statuses you were tracking
await Task.WhenAny(tasks);

// To cancel the rest of the tasks that are still waiting
cts.Cancel();

希望它有所帮助!

答案 1 :(得分:0)

如果在启动之前的时间跨度,WaitforStatus会抛出超时异常。

您可以在异常处理程序中检查当前和所需的状态,并执行您认为合适的任何操作。如果设置足够小的超时,则可以进行测试,然后根据需要退出或重试。

我不相信WaitforStatus支持多个同步条件,但让它过期,然后检查似乎非常接近你想要的。

答案 2 :(得分:0)

事实证明,ServiceController.WaitForStatus什么也不做,只是每0.25秒检查一次服务是否处于所需状态。 (来源:.NET Framework代码的反编译。)因此,如果尝试等待瞬态,则可能会错过它。因此,创建多个任务(和线程)以等待每个状态都是一个过大的选择。只需重现实际的.NET代码并更改返回条件即可。

    public static ServiceControllerStatus WaitForStates(this ServiceController service, TimeSpan timeout, params ServiceControllerStatus[] states)
    {
        //parameter checks omitted

        DateTime start = DateTime.UtcNow;

        while (true)
        {
            service.Refresh();

            ServiceControllerStatus currentState = service.Status;
            if (states.Contains(currentState))
                return currentState;

            TimeSpan elapsedTime = DateTime.UtcNow - start;
            if (elapsedTime > timeout)
                throw new TimeoutException();

            Thread.Sleep(250);
        }
    }