【问题标题】:Windows Service thread is not stopping in timely fashion in c#C# 中的 Windows 服务线程没有及时停止
【发布时间】:2014-02-27 11:22:36
【问题描述】:

我有一个使用 Thread 启动的 Windows 服务。作为 Windows 服务安装后,我能够正确启动该服务,但是一旦我尝试停止该服务,它就会花费太多时间并且不会停止。我正在使用ManualResetEvent 停止Windows 服务这是我的代码。

protected override void OnStart(string[] args)
    {
        _thread = new Thread(DoWork);
        _thread.Start();

    }
    private void DoWork()
    {

            while (!_shutdownEvent.WaitOne(0))
            {
                data = new byte[1024];
                int recv = sock.Receive(data);
                stringData = Encoding.ASCII.GetString(data, 0, recv);
            }
            sock.Shutdown(SocketShutdown.Both);
            sock.Close();
        }
        catch (Exception DFGFD)
        {
        }

    }

    protected override void OnStop()
    {
        _shutdownEvent.Set();
        _thread.Join();  // wait for thread to stop
    }
}

}

请帮我解决这个问题。

【问题讨论】:

  • 你的循环中有什么?会不会是socket关闭需要很长时间?
  • 您是否附加了调试器以查看导致问题的部分?
  • @Markus 是的,它是一个从套接字读取的套接字程序

标签: c# multithreading windows-services


【解决方案1】:

您的套接字阻塞了接收代码。我建议发布:

sock.Shutdown(SocketShutdown.Both);
sock.Close();

在从OnStop() 处理程序调用的方法中(因此它从另一个线程调用到阻塞Receive)。这将导致阻塞 sock.Receive 失败并出现异常,您可以通过退出循环来处理。

【讨论】:

  • 如果我是正确的应该写 sock.Shutdown(SocketShutdown.Both);袜子。关闭(); windows服务的OnStop()方法内的代码
  • @Pranav:是的,就是这样。
【解决方案2】:

可能while 中的代码是阻塞的(即同步等待来自连接的数据) 通常,您应该对套接字使用异步 I/O 操作,这通常可以避免启动新线程。

【讨论】:

【解决方案3】:

问题在于循环中对 Receive 的调用。来自MSDN:

如果没有数据可供读取,Receive 方法将阻塞 直到数据可用,除非使用设置超时值 套接字接收超时。如果超过超时值,接收 调用将抛出 SocketException。如果您处于非阻塞模式, 并且协议栈缓冲区中没有可用的数据, Receive 方法将立即完成并抛出一个 套接字异常。您可以使用 Available 属性来确定是否 数据可供读取。当可用非零时,重试 接收操作。

因此,我建议将循环中的代码更改为:

if (sock.Available > 0)
{
    data = new byte[1024];
    int recv = sock.Receive(data);
    stringData = Encoding.ASCII.GetString(data, 0, recv);
}
Thread.Sleep(200);

此代码检查数据是否可供读取,只有在有数据可供读取时才调用 Receive。为了避免忙等待,它发出调用Thread.Sleep。

如果你想避免调用Thread.Sleep,你可以在socket上指定一个ReceiveTimeout:

sock.ReceiveTimeout = 200;

while 循环中的代码将如下所示:

try
{
    data = new byte[1024];
    int recv = sock.Receive(data);
    stringData = Encoding.ASCII.GetString(data, 0, recv);
}
catch(SocketException ex)
{
    if (ex.SocketErrorCode != SocketError.TimedOut)
        throw;
    // In case of Timeout, do nothing, continue loop
}

【讨论】:

    【解决方案4】:

    问题: Receive() 正在等待其他输入。

    Thread.Join() 函数正在等待线程完成。

    可能的解决方案: 当我遇到类似情况时,我在 Join 函数 thread.Join(3000); 上使用了超时,这使线程有机会彻底关闭,然后继续。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多