4

I have the following method:

public bool ConnectAsync()
{
    if (IsConnected)
        throw new InvalidOperationException("Socket is already connected");

    if (IsConnecting)
    {
        throw new InvalidOperationException("Attempt to connect in progress");
    }

    . . .
}

Where:

    private readonly object padLock = new object();

    private bool isConnecting = false;

    public bool IsConnected
    {
        get
        {
            lock (padLock)
            { return socket.Connected; }
        }
    }

    public bool IsConnecting
    {
        get
        {
            lock (padLock)
            { return isConnecting; }
        }

        private set
        {
            lock (padLock)
            { isConnecting = value; }
        }
    }

enter image description here

Why the code inside the if statement is executed if my variable isConnecting is false?

Edit:
If I use the filed isConnecting instead of the property IsConnecting I have the same behavior. The code runs in the same thread anywhere.

Edit 2:

Finally this works:

lock (padLock)
{
    if (IsConnecting)
        throw new InvalidOperationException("Attempt to connect in progress");
}

And this works:

{
    if (IsConnecting)
        throw new InvalidOperationException("Attempt to connect in progress");
}

But why?

Nick
  • 10,309
  • 21
  • 97
  • 201
  • 1
    It looks to me like you're using multiple threads (else why the lock and the Async?) - if so, maybe you're looking at one thread's copy of isConnecting but execution stopped because another thread's copy is true. – prprcupofcoffee Nov 02 '12 at 20:54
  • @David in this test the thread is only the main thread. See edit. – Nick Nov 02 '12 at 20:55

4 Answers4

4

This is probably an issue with the debugger and multiple threads, try putting the lock around the outside of the if statement rather than inside the property.

gmn
  • 4,199
  • 4
  • 24
  • 46
  • Did you try moving the lock anyway? – gmn Nov 02 '12 at 20:59
  • 1
    You're right. This works +1 `lock (padLock) { if (IsConnecting) { ... } }`. Why? – Nick Nov 02 '12 at 21:01
  • I'm sure you must have multiple threads hitting that code at the same time causing the debugger to get confused causing a subtle race condition when debugging. – gmn Nov 02 '12 at 21:08
  • I'm sure I don't have multiple threads... `const int port = 11000; const string IP = "192.168.0.101"; static void Main(string[] args) { var client = new Client(IP, port); client.ConnectAsync(); Console.ReadLine(); }` – Nick Nov 02 '12 at 21:10
  • And if I had multiple threads the lock statement have to work correctly, and not in this way... – Nick Nov 02 '12 at 21:11
  • AFAIK, If you require thread-safe concurrent access to that boolean variable you still need to EXTERNALLY sycronise (i.e. serialise) access to the getter and setter methods. – corlettk Nov 03 '12 at 03:48
4

The Expression window you have in the debugger is the one triggering the exception, not your code. Remove expressions (or watch) and it should work as expected.

albattran
  • 1,887
  • 1
  • 12
  • 16
  • When you put a property in the watch window it needs to be evaluated. The only way to evaluate a property is to actually execute it, which in this case what the debugger is doing, hence the exception. – albattran Nov 03 '12 at 16:23
  • Also moving the locks outside like suggested above makes no difference - at least you shouldn't do it to change the current behavior. The reason why this worked is because you have set your breakpoint inside the lock (at which time the expression window is trying to evaluate your property), it is equivalent to moving your break point, it has nothing to do with changing the behavior of the code. – albattran Nov 03 '12 at 16:44
1

This answer explained the problem I was having: https://stackoverflow.com/a/27552124/1830461

Something of this format compiled to 64-bit can cause the debugger to step into the if statement:

        if (falseCondition) 
            throw new Exception(); 
        try { }  catch { }

It's a bug in Visual Studio. The code isn't actually executed. The solution is to just ignore it and continue stepping through the code. Putting a lock statement on it fixes it, because it is no longer in that format.

Community
  • 1
  • 1
bcwhims
  • 2,655
  • 2
  • 15
  • 15
0

I experienced this when I was debugging my code whilst the configuration mode was Release.

Simply setting the configuration mode to Debug resolved the issue.

enter image description here

YungDeiza
  • 3,128
  • 1
  • 7
  • 32