简体   繁体   English

如果你突破Lock()语句会发生什么?

[英]What happens if you break out of a Lock() statement?

I'm writing a program which listens to an incoming TcpClient and handles data when it arrives. 我正在编写一个程序,它监听传入的TcpClient并在数据到达时处理数据。 The Listen() method is run on a separate thread within the component, so it needs to be threadsafe. Listen()方法在组件内的单独线程上运行,因此它需要是线程安全的。 If I break out of a do while loop while I'm within a lock() statement, will the lock be released? 如果我break了一个的do while循环,而我是一个内lock()语句,将锁被释放? If not, how do I accomplish this? 如果没有,我该如何做到这一点?

Thanks! 谢谢!

(Any other advice on the subject of Asynchronous TCP Sockets is welcome as well.) (关于异步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);
}

Yes. 是。 The lock statement translates into a try/finally clause. lock语句转换为try / finally子句。 In C# 4, for example, a lock statement like so: 例如,在C#4中,锁定语句如下:

lock(obj)
{
    // body
}

roughly translates ( taken from Eric Lippert's blog here ) to: 大致翻译( 取自Eric Lippert的博客 )到:

bool lockWasTaken = false;
var temp = obj;
try 
{ 
    Monitor.Enter(temp, ref lockWasTaken); 
    { 
       // body 
    }
}
finally 
{ 
    if (lockWasTaken) 
        Monitor.Exit(temp); 
}

When the execution leaves the scope of the lock {} , the underlying lock will be released automatically. 当执行离开lock {}的范围时,底层锁将自动释放。 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. 无论你如何退出范围(break / return / etc),都会发生这种情况,因为对Monitor.Exit的调用是在try / finally的finally块内部包装的。

Yes, the lock will be released. 是的,锁将被释放。 You can use ILDASM or Reflector to look at the actual generated code. 您可以使用ILDASM或Reflector查看实际生成的代码。 The lock statement is shorthand for the following code (roughly). lock语句是以下代码的简写(粗略)。

Monitor.Enter(_client);
try
{
  // do your stuff

}
finally {
  Monitor.Exit(_client);
}

Notice the finally block is always executed. 请注意,始终执行finally块。

Once you exit the lock{} , it will unlock what you have locked (it's just like a using statement in that regard). 退出lock{} ,它将解锁您锁定的内容(就像在这方面的使用声明一样)。 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. 想想如果你在中间引发异常会发生什么。

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. 这是值得注意的事情,因为它容易出错。

To answer the other half of your question: 要回答你问题的另一半:

Any other advice on the subject of Asynchronous TCP Sockets is welcome as well 关于异步TCP套接字主题的任何其他建议也是受欢迎的

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. 而是从System.Net.Sockets.TcpClient和System.Net.Sockets.TcpListener类中寻求帮助。 Use the async calls like BeginAcceptSocket(...) and BeginRead(...) and allow the ThreadPool to do it's job. 使用像BeginAcceptSocket(...)和BeginRead(...)这样的异步调用,并允许ThreadPool完成它的工作。 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" :) 您应该能够实现所需的所有服务器行为,而无需编写可怕的单词“new Thread”:)

Here is a basic example of the idea, minus the idea of graceful shutdown, exception handling ect: 以下是该想法的基本示例,减去正常关闭,异常处理等的想法:

public static void Main()
{
    TcpListener listener = new TcpListener(new IPEndPoint(IPAddress.Loopback, 8080));
    listener.Start();
    listener.BeginAcceptTcpClient(OnConnect, listener);

    Console.WriteLine("Press any key to quit...");
    Console.ReadKey();
}

static void OnConnect(IAsyncResult ar)
{
    TcpListener listener = (TcpListener)ar.AsyncState;
    new TcpReader(listener.EndAcceptTcpClient(ar));
    listener.BeginAcceptTcpClient(OnConnect, listener);
}

class TcpReader
{
    string respose = "HTTP 1.1 200\r\nContent-Length:12\r\n\r\nHello World!";
    TcpClient client;
    NetworkStream socket;
    byte[] buffer;

    public TcpReader(TcpClient client)
    {
        this.client = client;
        socket = client.GetStream();

        buffer = new byte[1024];
        socket.BeginRead(buffer, 0, 1024, OnRead, socket);
    }

    void OnRead(IAsyncResult ar)
    {
        int nBytes = socket.EndRead(ar);
        if (nBytes > 0)
        {
            //you have data... do something with it, http example
            socket.BeginWrite(
                Encoding.ASCII.GetBytes(respose), 0, respose.Length, null, null);

            socket.BeginRead(buffer, 0, 1024, OnRead, socket);
        }
        else
            socket.Close();
    }
}

For a much more complicated example of how to do this see the SslTunnel Library I wrote a while ago. 有关如何执行此操作的更复杂示例,请参阅我刚才写的SslTunnel库

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM