如果突破 Lock() 语句会发生什么?
我正在编写一个程序,它侦听传入的 TcpClient 并在数据到达时处理数据。 Listen()
方法在组件内的单独线程上运行,因此它需要是线程安全的。如果我在 lock()
语句中 break
退出 do
while
循环,锁被释放?如果没有,我该如何实现这个目标?
谢谢!
(也欢迎有关异步 TCP 套接字主题的任何其他建议。)
private void Listen()
{
do
{
lock (_clientLock)
{
if (!_client.Connected) break;
lock (_stateLock)
{
if (!_listening) break;
if (_client.GetStream().DataAvailable) HandleData();
}
}
Thread.Sleep(0);
} while (true);
}
I'm writing a program which listens to an incoming TcpClient and handles data when it arrives. The Listen()
method is run on a separate thread within the component, so it needs to be threadsafe. If I break
out of a do
while
loop while I'm within a lock()
statement, will the lock be released? If not, how do I accomplish this?
Thanks!
(Any other advice on the subject of Asynchronous TCP Sockets is welcome as well.)
private void Listen()
{
do
{
lock (_clientLock)
{
if (!_client.Connected) break;
lock (_stateLock)
{
if (!_listening) break;
if (_client.GetStream().DataAvailable) HandleData();
}
}
Thread.Sleep(0);
} while (true);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的。 lock 语句转换为 try/finally 子句。例如,在 C# 4 中,类似这样的 lock 语句:
粗略翻译为 (摘自 Eric Lippert 的博客):
当执行离开
lock {}
的范围时,底层锁将自动释放。无论您如何退出作用域(break/return/etc),这种情况都会发生,因为对 Monitor.Exit 的调用在内部包装在 try/finally 的 finally 块内。Yes. The lock statement translates into a try/finally clause. In C# 4, for example, a lock statement like so:
roughly translates (taken from Eric Lippert's blog here) to:
When the execution leaves the scope of the
lock {}
, the underlying lock will be released automatically. This will happen no matter how you exit scope (break/return/etc), since the call to Monitor.Exit is wrapped, internally, inside of the finally block of a try/finally.是的,锁将会被释放。您可以使用 ILDASM 或 Reflector 查看实际生成的代码。 lock 语句是以下代码的简写(大致)。
请注意,finally 块始终会被执行。
Yes, the lock will be released. You can use ILDASM or Reflector to look at the actual generated code. The lock statement is shorthand for the following code (roughly).
Notice the finally block is always executed.
因为你寻求其他建议......我注意到你正在嵌套锁。这本身并不一定是一件坏事。但是,这是我要注意的危险信号之一。如果您在代码的另一部分以不同的顺序获取这两个锁,则可能会出现死锁。我并不是说你的代码有什么问题。这只是需要注意的其他事情,因为很容易出错。
Because you asked for other advice...I noticed that you are nesting locks. This, by itself, is not necessarily a bad thing. But, it is one my red flags I watch out for. There is the possibility of a deadlock if you ever acquire those two locks in a different order in another part of your code. I am not saying there is anything wrong with your code. It is just something else to watch out for because it is easy to get wrong.
一旦您退出
lock{}
,它将解锁您已锁定的内容(在这方面,它就像一个 using 语句)。你从哪里退出(开始、结束或中间)并不重要,重要的是你完全离开了锁的范围。想想如果你在中间抛出异常会发生什么。Once you exit the
lock{}
, it will unlock what you have locked (it's just like a using statement in that regard). It doesn't matter where you exit (the beginning, the end, or the middle), it's that you left the scope of the lock at all. Think about what would happen if you raised an exception in the middle.回答你问题的另一半:
简单地说,我不会按照您原来的帖子演示的方式来管理这个问题。而是从 System.Net.Sockets.TcpClient 和 System.Net.Sockets.TcpListener 类寻求帮助。使用像 BeginAcceptSocket(...) 和 BeginRead(...) 这样的异步调用,并允许 ThreadPool 完成它的工作。这样组合起来真的很容易。
您应该能够实现您想要的所有服务器行为,而无需编写可怕的单词“new Thread”:)
这是这个想法的一个基本示例,减去优雅关闭、异常处理等的想法:
对于一个更复杂的示例有关如何执行此操作的信息,请参阅 SslTunnel 库 我不久前写的。
To answer the other half of your question:
Simply put I wouldn't manage this in the fashion demonstrated by your original post. Rather seek help from the System.Net.Sockets.TcpClient and the System.Net.Sockets.TcpListener classes. Use the async calls like BeginAcceptSocket(...) and BeginRead(...) and allow the ThreadPool to do it's job. It's really pretty easy to put together that way.
You should be able to achieve all the server behavior you desire without ever coding the dreaded words "new Thread" :)
Here is a basic example of the idea, minus the idea of graceful shutdown, exception handling ect:
For a much more complicated example of how to do this see the SslTunnel Library I wrote a while ago.