我的应用程序运行占用大量CPU的算法来编辑放置在WPF窗口中的图像。我需要的编辑是在一个后台线程。然而,试图在非UI线程中编辑WritableBitmap的BackBuffer会抛出InvalidOperationException。
private WriteableBitmap writeableBitmap;
private void button1_Click(object sender, RoutedEventArgs e)
{
// Create WritableBitmap in UI thread.
this.writeableBitmap = new WriteableBitmap(10, 10, 96, 96, PixelFormats.Bgr24, null);
this.image1.Source = this.writeableBitmap;
// Run code in non UI thread.
new Thread(
() =>
{
// 'Edit' bitmap in non UI thread.
this.writeableBitmap.Lock(); // Exception: The calling thread cannot access this object because a different thread owns it.
// ... At this place the CPU is highly loaded, we edit this.writeableBitmap.BackBuffer.
this.writeableBitmap.Unlock();
}).Start();
}我已经读了几十本手册,它们都告诉我在UI线程(即MSDN)中做BackBuffer版。
如何在没有任何无用的缓冲区复制/克隆的情况下在非UI线程中编辑WritableBitmap.BackBuffer?
发布于 2012-09-26 00:46:23
在后台线程中写入到后台缓冲区的MSDN suggests。只需要在UI线程上执行某些更新前和更新后操作。因此,当后台线程执行实际更新时,UI线程可以自由执行其他操作:
//Put this code in a method that is called from the background thread
long pBackBuffer = 0, backBufferStride = 0;
Application.Current.Dispatcher.Invoke(() =>
{//lock bitmap in ui thread
_bitmap.Lock();
pBackBuffer = (long)_bitmap.BackBuffer;//Make pointer available to background thread
backBufferStride = Bitmap.BackBufferStride;
});
//Back to the worker thread
unsafe
{
//Carry out updates to the backbuffer here
foreach (var update in updates)
{
long bufferWithOffset = pBackBuffer + GetBufferOffset(update.X, update.Y, backBufferStride);
*((int*)bufferWithOffset) = update.Color;
}
}
Application.Current.Dispatcher.Invoke(() =>
{//UI thread does post update operations
_bitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, width, height));
_bitmap.Unlock();
});发布于 2012-03-26 17:34:40
正如克莱门斯所说,这是不可能的。
您有三个选择:
1)按照Clemens的建议,在缓冲区中进行编辑,并在编辑完成后进行blit。
2)以非常小的块进行编辑,并在GUI线程上以很好的优先级调度它们。如果您保持工作块足够小,GUI将保持响应,但显然这会使编辑代码变得复杂。
3)组合1和2。在另一个线程中编辑小块,然后在完成时对每个块进行blit。这使GUI在不使用内存作为完全后台缓冲区的情况下保持响应。
发布于 2012-03-26 17:13:20
除了Klaus78所说的之外,我还建议采取以下方法:
byte[])上执行异步“位图编辑”代码。不要在每次需要执行异步操作时都创建新的Thread。这就是ThreadPool诞生的目的。示例:
private byte[] buffer = new buffer[...];
private void UpdateBuffer()
{
ThreadPool.QueueUserWorkItem(
o =>
{
// write data to buffer...
Dispatcher.BeginInvoke((Action)(() => writeableBitmap.WritePixels(..., buffer, ...)));
});
}https://stackoverflow.com/questions/9868929
复制相似问题