Dispatcher.Invoke的竞争条件
本文关键字:条件 竞争 Invoke Dispatcher | 更新日期: 2023-09-27 18:11:52
我有一个WritableBitmap,我想得到它的尺寸。因为对象由另一个线程拥有,所以我们必须通过Dispatcher。我试过了:
int targetPixelWidth = 0;
int targetPixelHeight = 0;
writeableBitmap.Dispatcher.Invoke(new Action(() =>
{
targetPixelWidth = writeableBitmap.PixelWidth;
targetPixelHeight = writeableBitmap.PixelHeight;
}));
// Do something with targetPixelWidth and targetPixelHeight
然而,这有时会失败:值通常保持为0,即使实际值不同。
考虑到这可能是线程问题,我将代码更改如下:
var bitmapInfo = (Tuple<int, int>)writeableBitmap.Dispatcher.Invoke(new Func<Tuple<int, int>>(
() => Tuple.Create(writeableBitmap.PixelWidth, writeableBitmap.PixelHeight)
));
Debug.Assert(bitmapInfo != null, "Obviously, this should pass.");
targetPixelWidth = bitmapInfo.Item1;
targetPixelHeight = bitmapInfo.Item2;
// Do something with targetPixelWidth and targetPixelHeight
但现在,bitmapInfo
有时为空。这很奇怪,因为(根据文档)Invoke
应该只在委托没有返回值时返回null,在这种情况下它显然是这样做的。我甚至把Debug.Assert
的返回值改为Tuple.Create
的返回值,而且它从来没有为空。
我在这里错过了什么?是什么导致了这种竞态,我能做些什么?
EDIT
很抱歉给出了错误的答案。
似乎你想从另一个线程中获得gui线程中的WriteableBitmap的依赖属性。
你可以试试:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var writeableBitmap = new WriteableBitmap(100, 100, 300, 300, PixelFormats.Bgra32, null);
_image.Source = writeableBitmap;
new Thread(() =>
{
Thread.Sleep(1000);
var pixelHeigth = (Int32)writeableBitmap.Dispatcher.Invoke(
DispatcherPriority.Background,
(DispatcherOperationCallback)(arg => ((WriteableBitmap)arg).PixelHeight), writeableBitmap);
Debug.Print("PixelHeight:" + pixelHeigth);
}).Start();
}
我刚试过,效果很好
这行得通,虽然我不知道为什么:
ManualResetEventSlim mre = new ManualResetEventSlim(false);
int targetPixelWidth = 0;
int targetPixelHeight = 0;
writeableBitmap.Dispatcher.Invoke(new Action(() =>
{
try {
targetPixelWidth = writeableBitmap.PixelWidth;
targetPixelHeight = writeableBitmap.PixelHeight;
}
finally {
mre.Set();
}
}));
mre.Wait();
// Do something with targetPixelWidth and targetPixelHeight
有人(谁张贴了这个问题的答案,但后来删除了它),建议Invoke
是同步的GUI线程,而不是在调用Invoke
的线程。如果这是真的,这就解释了为什么它有效。然而,文档、书籍[1,2]和试图重现这个问题的小玩具程序都表明情况并非如此;Invoke
在调用线程上应该是同步的。
我还没能想出一个真正的解释;如果有人有,我洗耳恭听:)。
EDIT用更连贯的东西替换我原来的,有点散乱的答案