4

There's some non-optimal code in a program like this (Pseudo code to give you an idea):

public void button1_click()
{
     picturebox1.Image = someBitmap;
     someBitmap.LockBits(...);
     Parallel.For(..., () => DoSomethingWith(someBitmap));
     someBitmap.UnlockBits(...);
}

From time to time, the program crashes, saying that the bitmap is already locked. I don't need debugging help and I don't need code to fix the problem. I can easily fix it.

What bothers me more is the fact that I don't understand how that can happen. IMHO the UI thread is blocked. No windows messages should be able to be processed while the button1_click method is executing. Unless, of course, someone calls DoEvents(), which is not the case.

Still, when I look at the call stack, it shows this:

1

As you can see, the Parallel.For() call is still on the stack. It's not completed yet. The .NET code reached a ManualResetEventSlim and should be waiting. From MSDN I can't see that the Wait() methods do message dispatching.

Still, at that point, a WM_PAINT message got processed, causing the picture box to access the bitmap while that bitmap is still locked by LockBits().

What's going on here? Where's my understanding of UI thread blocking wrong?

@Dai asked whether this only happens during debugging. Indeed that seems to be true. I gave it 10 runs and it never crashed. So it seems the debugger is not my friend this time.

Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • Does this only happen when you're in the VS Debugger? I noticed the call goes through `DebuggableCallback` which I think is called by Visual Studio itself, it won't be called when your program runs without a debugger attached. – Dai Oct 24 '18 at 20:34
  • 1
    BTW, I'd put the `someBitmap.UnlockBits` call inside a `finally` block. – Dai Oct 24 '18 at 20:34
  • @Dai: it seems you're right. It does not happen outside the debugger (at least during the last 6 runs I just tried) – Thomas Weller Oct 24 '18 at 20:38

1 Answers1

1

There are several ways to achieve this:

When you are waiting some messages are still pumped. This includes COM messages which are seemingly also used by the debugger. The message pumping behavior of Windows Forms and WPF has changed several times since .NET 4.0. It can hit your application at any time if you are called via UI automation libraries if you have pending posted messages.

Alois Kraus
  • 13,229
  • 1
  • 38
  • 64