1

我正在使用 WPF 成像来使用 DrawingVisual 将文本、3d 图形和图像合成在一起。然后将结果呈现为 RenderTargetBitmap 并以 jpeg 格式保存到磁盘。所有这些都发生在没有可视窗口的代码中。

只要我一次只尝试做一件事,它就可以很好地工作。但是,我想看看是否可以通过使用多个线程进行渲染来加快速度。每个线程都使用一个创建自己的 DrawingContext、DrawingVisual 等的对象。但是,当我尝试并行访问它们时,显然在某处存在一些共享状态,因为我得到了虚假错误。有时它是“调用线程无法访问此对象,因为另一个线程创建了它”。其他时候,当我添加指向 3D 几何图形时,从 WPF 的内部冒出的 NullReferenceExceptions 看起来更邪恶。

有没有办法确保每个线程与 WPF 保持隔离?还是共享状态是不可避免的?

4

3 回答 3

0

您是否可能不小心跨线程使用了相同的资源?您的处理代码中是否涉及任何 lamda 表达式或匿名方法?

于 2012-07-27T01:27:45.780 回答
0

尤里卡。我在线程池线程中创建我的对象,这在使用 WPF 时显然是一个禁忌。相反,所有对象都需要从调度程序线程中创建。顺便说一句,这也清除了我没有发现的可怕的内存泄漏。

我原来的类定义是这样的:

public class Compositor
{
    private int _width;
    private int _height;
    private DrawingVisual _drawingVisual;
    private DrawingContext _drawingContext;
    private bool _isReady = false;
    public void Reset(int width, int height)
    {
        _width = width;
        _height = height;
        _drawingVisual = new DrawingVisual();
        _drawingContext = _drawingVisual.RenderOpen();
        _isReady = true;
    }
    // ... compositing methods below
}

为了纠正,我让我的类继承自DispatcherObject,然后使用该Dispatcher属性来实例化我的对象。

public class Compositor : DispatcherObject
{
    private int _width;
    private int _height;
    private DrawingVisual _drawingVisual;
    private DrawingContext _drawingContext;
    private bool _isReady = false;
    public void Reset(int width, int height)
    {
        Dispatcher.Invoke(
            new Action(
                () =>
                    {
                        _width = width;
                        _height = height;
                        _drawingVisual = new DrawingVisual();
                        _drawingContext = _drawingVisual.RenderOpen();
                        _isReady = true;
                    }));
    }
    // ... compositing methods below
}
于 2012-07-27T07:45:54.463 回答
0

来自MSDN

从 DispatcherObject 派生的对象具有线程亲和性。

从 Freezable 派生的对象在冻结时是自由线程的。有关详细信息,请参阅可冻结对象概述。

在处理应该在 UI 线程上真正使用(不仅是创建)的位图、画笔和其他类时,我也遇到过类似的问题。

这很烦人,因为人们想利用 WPF 渲染的力量来并行处理领域,但这似乎是不可能的(除了一些场景,比如WriteableBitmap使用指针更新)。

于 2013-07-14T06:01:29.127 回答