解决 异步方法没有't work

龙4ik

会员
已加入
2020年10月24日
留言内容
16
编程经验
Beginner
我遇到了这个问题,试图为函数执行设置超时。

我有以下代码:
Function call:
public BitmapImage[,] GetResult(List<BitmapImage> 清单)
        {
            var task = Task.Run(() => GetBestPuzzleImage(list));
            if (task.Wait(TimeSpan.FromSeconds(10)))
                return task.Result as BitmapImage[,];
            else
                throw new Exception("Timed out");
        }

方法 GetBestPuzzleImage() 创建函数的大调用堆栈,其中参数 清单 继续在函数中传递,直到达到终点 GetPixels(),我尝试获取每个格式 清单的 元件。还有那个地方 System.InvalidOperationException:'调用线程无法访问此对象,因为另一个线程拥有它。 被抛出:
C#:
private PixelColor[,] GetPixels(BitmapSource source)
        {
                if (source.Format != PixelFormats.Bgra32)      //here exception is thrown
                {
                    source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
                }

                int width = source.PixelWidth;
                int height = source.PixelHeight;
                PixelColor[,] result = new PixelColor[width, height];

                source.CopyPixels(result, width * 4, 0, true);

                return result;
        }

这是来自UI线程的函数调用:
C#:
var arr = alghoritm.GetResult(bmp);

我尝试使用 冻结() 使对象跨线程的方法如下:
C#:
private PixelColor[,] GetPixels(BitmapSource source)
{
    source.Freeze();
    var temp = source.Clone();
    
    //and then code works with "temp" value
}

但是什么都没有改变。因此,我想知道为什么会发生此问题以及如何解决?
 
Solution
If your code is in a Window then the Window itself provides the ability to marshal a call to the UI thread. There's no specific need to use the control you want to affect. Any control created on that same thread will do.

If your code is not directly UI-aware then you can use the SynchronizationContext class. Basically, you initialise a field of that type using SynchronizationContext.Current and you can always use that field to marshal a method call back to the thread that the current object was created on. Obviously, you would need to have created the current object on the UI thread for that to be useful.

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,921
地点
英国
编程经验
10+
In your method : private PixelColor[,] GetPixels(BitmapSource source) you will need to 调用 物体。

您尝试访问的对象是在另一个线程的其他位置创建的。您需要委派回创建对象的线程。您可以在此处找到一些示例代码,在此我将解释如何执行此操作: 已回答-IF Else关于标签背景色的声明。

I try to use to use 冻结() 使对象跨线程的方法如下:
冻结不用于该目的。我记得这是为了防止对项目进行修改。通过执行新任务的代码而不用另一种方法锁定对象,您已经被足够的阻止。
 

龙4ik

会员
已加入
2020年10月24日
留言内容
16
编程经验
Beginner
In your method : private PixelColor[,] GetPixels(BitmapSource source) you will need to 调用 物体。

您尝试访问的对象是在另一个线程的其他位置创建的。您需要委派回创建对象的线程。您可以在此处找到一些示例代码,在此我将解释如何执行此操作: 已回答-IF Else关于标签背景色的声明。


冻结不用于该目的。我记得这是为了防止对项目进行修改。通过执行新任务的代码而不用另一种方法锁定对象,您已经被足够的阻止。
我尝试了您的解决方案,首先,我意识到了 位图源 不包含任何定义 调用() 方法。所以我创建了PixelDelagate:
C#:
private delegate PixelColor[,] PixelDelegate(BitmapSource el);
然后这样打电话给他:
C#:
private 位图源 GetRightImage(BitmapSource first, 清单<BitmapSource> 清单, ref double totalDifference)
{
            PixelDelegate pixelDelegate = GetPixels;
            PixelColor[,] left = pixelDelegate.Invoke(first);
            //TODO:
}
也许我错误地解释了您的解决方案,因为继续抛出异常。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,498
地点
悉尼,澳大利亚
编程经验
10+
Note that, these days, you pretty much never have to declare your own delegate types. Just use the appropriate Action (for void methods) or Func. In your case, a Func<BitmapSource, PixelColor[,]> would do the job.
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,498
地点
悉尼,澳大利亚
编程经验
10+
If your code is in a Window then the Window itself provides the ability to marshal a call to the UI thread. There's no specific need to use the control you want to affect. Any control created on that same thread will do.

If your code is not directly UI-aware then you can use the SynchronizationContext class. Basically, you initialise a field of that type using SynchronizationContext.Current and you can always use that field to marshal a method call back to the thread that the current object was created on. Obviously, you would need to have created the current object on the UI thread for that to be useful.
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,921
地点
英国
编程经验
10+
我仍然声明它们的唯一原因是为了简化OP的阅读。但是正确的是。
 
最佳 底部