I've just encountered my first numbskull deadlock condition, and it was all my fault. It's all to do with the SMS modem driver I'm writing. I've hooked up this event to the System.IO.Ports.SerialPort's data received event:

private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    lock (incomingBuffer)
    {
        string data = port.ReadExisting();
        incomingBuffer += data;
    }
    CheckForIncomingMessage();
}


Then CheckForIncomingMessage() does this:

private void CheckForIncomingMessage()
{
    string response = PeekResponseLine();
    if (response.Contains(GsmResponses.MessageReceived))
    {
        EraseFromBuffer(response);
        int commaIndex = response.IndexOf(',');
        string messageIndexText = response.Substring(commaIndex, response.Length - commaIndex);
        int messageIndex;
        if (int.TryParse(messageIndexText, out messageIndex))
        {
            OnMessageReceived(messageIndex);
        }
    }
}


Just for completeness sake, and completely relevant to the problem at hand, here's PeekResponseLine() and EraseFromBuffer():

private string PeekResponseLine()
{
    while (true)
    {
        string bufferCopy = string.Empty;
        lock (incomingBuffer)
        {
            bufferCopy = incomingBuffer;
        }
        int length = bufferCopy.IndexOf("\r\n");
        if (length > -1)
        {
            if (bufferCopy.Contains(GsmResponses.MessageTextWanted))
                length = GsmResponses.MessageTextWanted.Length;
            else
                length += 2;
            string response = bufferCopy.Substring(0, length);
            return response;
        }
    }
}


private void EraseFromBuffer(string message)
{
    lock (incomingBuffer)
    {
        incomingBuffer = incomingBuffer.Remove(0, message.Length);
    }
}


Seen the problem yet? If you investigate the documentation for SerialPort in MSDN (or just crack it open in Reflector for the sake of it), you'll notice that the data recevied event fires on a different thread to your code that owns the serial port instance.

Initially I though it was some kind of deadlock condition between the main thread and the data receive thread as they are both trying to grab a lock on the incomingBuffer quite frequently. Alas, the true problem is much more obvious and a lot more stupid than that.

The key to it is in the PeekResponseLine() method. It's still a deadlock of sorts, but it's a self deadlock. I'm holding the data received thread to ransom by doing a while(true) on it. Because I never leave the PeekResponseLine() method, I never give the data recevied thread a chance to pluck the data off the serial port.