2

I need to update the pixels of the image asynchronously. I have a problem with a solution that was suggested in this topic - topic. So, the following code called from non UI thread. The application stops responding during the execution of this code:

Dispatcher.Invoke(() =>
{
_bitmap.Lock();
pBackBuffer =_bitmap.BackBuffer;
});

unsafe
{
    Marshal.Copy(_displayPixels, 0, pBackBuffer, _displayPixels.Length);   
} 

Dispatcher.Invoke(() =>
{
_bitmap.AddDirtyRect(new Int32Rect(0, 0, DepthWidth, DepthHeight));
_bitmap.Unlock();
});

What am I do wrong?

Community
  • 1
  • 1
CyberDreamer
  • 81
  • 1
  • 7
  • As a result I using `_bitmap.WritePixels` in UI thread without `Lock\Unlock` and data manipultaion in another thread. It's work! – CyberDreamer May 30 '15 at 01:42

2 Answers2

2

Stop cargo culting. The unsafe block is completely useless, remove it.

That said, _bitmap.Lock() and _bitmap.Unlock() are far from cheap. Did you profile the application? I'm pretty sure most of the time is spent in the Invoke calls, which do run on the UI thread.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • thanks for the advice.Profiler says that `PresentationFramework.dll` have 42% exclusive samples, but not from `_bitmap.Lock()`. It is not hot line. But if it's true. What is an alternative not to use `Lock`? – CyberDreamer May 28 '15 at 14:55
  • @CyberDreamer Reading profiler results in code like this is tricky - it's basically telling you that 42% of the work is in those `Invoke` calls (excluding the actual time spent inside the delegates, possibly - it's hard to tell). And in a way, there is no alternative - you're copying the full bitmap as a single operation; there's no place to shave off execution time. The truth is, I don't see why you're touching the backbuffer at all - why not just swap the bitmap for another bitmap when you already have it ready? – Luaan May 28 '15 at 15:01
  • I thought about it and did the following. Create image in one non UI thread and updated in other non UI thread through the `Dispatcher`. But i had `InvalidOperationException - The calling thread cannot access this object because a different thread owns it` on `_bitmap.Unlock()`. How it's passible? – CyberDreamer May 28 '15 at 18:35
  • @CyberDreamer You can only use it on the thread where it was created. Maybe you don't want to use `WriteableBitmap` at all? – Luaan May 28 '15 at 21:30
  • Wow, even if I don't use UI thread and call `Lock/Unlock` through Dispatcher is not going to work? Where can I read about such details? What alternative for `WritableBitmap`? – CyberDreamer May 29 '15 at 00:07
  • I need to update Bitmap 30 times per second. Every time allocate memory for this is not cool. So how can I get memory allocate only once and multiple use in another thread? – CyberDreamer May 29 '15 at 00:16
  • @CyberDreamer Try this - https://writeablebitmapex.codeplex.com/ it should allow you to blit, which should be enough for you. Or just use `WritePixels`, it might be faster than your approach. It's hard to tell. – Luaan May 29 '15 at 05:26
  • Thank you for your many answers. But... Now i have a new trouble or variant of original problem. I use `writePixels` without Lock\Unlock and application don't stops responding. But i don't see change of image on the screen. I even use a InvalidationVisual in WPF controls as analog Refresh in WinForms. – CyberDreamer May 29 '15 at 07:13
  • @CyberDreamer Are you sure that you're actually writing pixels that are different? – Luaan May 29 '15 at 07:17
  • Yes. Even if i do only a single thread, the version with `Lock\Marshal.Copy\ Unlock` works well, but with `WritePixels` gives a static white screen. – CyberDreamer May 29 '15 at 18:54
  • Oh, it's my mistake. You will right. As a result I using `WritePixels` in UI thread, but data manipultaion in another thread. Thanks! – CyberDreamer May 30 '15 at 01:40
0

Try with Dispatcher.BeginInvoke instead of Dispatcher.Invoke to run it asynchronously.

Gopichandar
  • 2,742
  • 2
  • 24
  • 54
  • That's a terrible idea. This needs to run synchronously to work at all, and even if it didn't, that would still block the GUI thread for the duration of the `BeginInvoke`. The problem isn't blocking the non-GUI thread - it's the GUI thread that's trouble. – Luaan May 28 '15 at 14:10