C# 中止阻塞线程的正确方法
我正在创建一个包含TCP连接的服务器。TCP连接在其自己的线程中无限期运行。是否有一个好的模式允许安全关闭TcpListener和客户机以及线程?以下是我到目前为止的情况C# 中止阻塞线程的正确方法,c#,.net,multithreading,design-patterns,C#,.net,Multithreading,Design Patterns,我正在创建一个包含TCP连接的服务器。TCP连接在其自己的线程中无限期运行。是否有一个好的模式允许安全关闭TcpListener和客户机以及线程?以下是我到目前为止的情况 private volatile bool Shudown; void ThreadStart1() { TcpListener listener = null; TcpClient client = null; Stream s = null; try { liste
private volatile bool Shudown;
void ThreadStart1()
{
TcpListener listener = null;
TcpClient client = null;
Stream s = null;
try
{
listener = new TcpListener(60000);
client = listener.AcceptTcpClient();
Stream s = client.GetStrea();
while(!Shutdown) // use shutdown to gracefully shutdown thread.
{
try
{
string msg = s.ReadLine(); // This blocks the thread so setting shutdown = true will never occur unless a client sends a message.
DoSomething(msg);
}
catch(IOException ex){ } // I would like to avoid using Exceptions for flow control
catch(Exception ex) { throw; }
}
}
catch(Exception ex)
{
LogException(ex);
throw ex;
}
finally
{
if(listener != null) listener.Close();
if(s != null) s.Close();
if(client != null) client.Close();
}
}
在网络流上设置超时(client.ReadTimeout=…)。读取操作超时后,检查主线程是否发出停止的信号(通过设置变量或AutoResetEvent)。如果有停止的信号,优雅地退出。如果没有,请尝试再次读取,直到下一个超时 设置0.5秒或1秒的超时时间就足够了-您将能够及时退出线程,并且在CPU上非常轻松 是否有一个好的模式允许安全关闭线程 将while循环更改为以下内容:
while (!interrupted){
// Do something
}
// declare interrupted as volatile boolean
volatile bool interrupted;
查看此项了解详细信息。
当检查while条件时,将interrupted boolean设置为true将使线程退出循环
是否有一个良好的模式允许安全关闭TcpListener和
客户
为避免重复,请检查此项
至于您关于如何在
ReadLine()上终止阻塞线程的问题代码>下面的listener.Server.Close()
应该执行此任务并从阻塞调用返回。也许不应该同步调用NetworkStream对象上的Read,而应该使用BeginRead和EndRead异步执行,并在完成NetworkStream时调用Close() 你的catch子句是多余的。这不是你问题的解决方案,但它仍然是多余的。你的权利。我编辑以显示我的真实意图。同样,你不应该抛出ex,因为那样会重置堆栈跟踪。试着改用justthrow
。请参阅:如果我错了,请纠正我的错误,但在线程运行时中止线程从来都不是一个好主意(即使它是可能的)。更好的建议是重新编写代码以读取变量,如果变量设置为true,线程可以中断任何循环/等待并完成执行,因此不一定要中止它。@mazzz:您建议如何解决该问题?我意识到中止线程是不好的。这就是为什么我要求一种优雅的方法来处理终止线程的同时也优雅地终止tcp连接的原因。请告诉我,这也是我的解决方案,只需捕获异常并确保它是一个超时错误(如果是其他错误,请抛出它)如果变量仍然为false,则继续循环,该变量将引发异常。如何在不断开连接的情况下处理?如果有一个超时选项,该选项不引发连接,而是返回null或类似的值,以允许在给定的时间间隔内取消阻止线程,那就太好了。当异常关闭时,连接不会关闭。捕获IOException,确保它是一个超时(查看HRESULT),然后继续在循环中读取。由于异常非常昂贵,我宁愿在流控制中避免它们。Tcp连接需要具有相当高的响应速度(~1-2ms)。通常情况下,异常不应用于流控制。如果不活动,则在一秒钟后您正在处理异常。我认为这是可以商量的。如果不是,则完全删除后台线程并切换到异步IO(使用BeginRead而不是Read并提供回调),这是用于安全线程关闭的注释模式。但这并不能解决问题。如果线程被Stream.ReadLine()阻塞,如何告诉线程它被中断?我将更新这个问题以显示我在说什么。来自另一个线程的listener.Server.Close()将中断ReadLine阻塞调用。真的吗?我没想过要试一下。我看看这是否有效。如果这符合我的需要,您可以创建一个答案,我将接受它作为解决方案。使用Server.Close()是正确的答案。任何阻塞方法都将使用ObjectDisposedException完成。@Neal Done!我希望这有帮助。