代码之家  ›  专栏  ›  技术社区  ›  Ski

线程化图像缩放子仍会阻塞UI

  •  1
  • Ski  · 技术社区  · 16 年前

    我为我的老板创建了一个图像查看控件,它包括平移、通过鼠标滚轮缩放以及绘制一个要缩放的框。控件需要支持非常大的图像文件(即每侧数千像素)。

    一切正常,但当代码缩放图像时,控件用户界面将失去响应。我的老板让我用线程把缩放代码与用户界面分开。缩放代码现在肯定在一个单独的线程上,但是当缩放代码运行时,UI仍然陷入困境!有人能帮我吗?是吗?

    下面是缩放代码。如果这不足以帮助我,请告诉我,我将发布您需要的任何代码!

    更新:这里是整个控制代码。 link text

    4 回复  |  直到 16 年前
        1
  •  0
  •   Komat    16 年前

    似乎gdi+api中存在一些全局锁。对于测试,我基于以下函数创建了两个线程

    static void test_thread()
    {
        Bitmap bmp = new Bitmap( 4000, 4000 );
        Graphics g = Graphics.FromImage( bmp );
        Brush b = Brushes.Red ;
    
        for ( ; ; ) {
            g.FillRectangle( b, 0, 0, bmp.Width, bmp.Height );
        }
    }
    

    如果无限循环的ben为空,则CPU使用率超过90%,因此它们使用了我的CPU的两个核心。在FillRectangle存在的情况下,用法略低于50%,表示一次只能运行一个线程。

    因此,在缩放过程中,从GUI线程执行的任何GDI+调用都可能会阻塞,直到缩放完成。

        2
  •  0
  •   Gregor Brandt    16 年前

    我怀疑由于扩展使用了所有的CPU,所以用户界面陷入了困境。两个线程的优先级可能相同。

    尝试降低缩放线程的优先级以允许用户界面响应。

    Values for Thread Priority:
    
    Above Normal -> Gives thread higher priority
    Below Normal ->Gives thread lower priority
    Normal -> Gives thread normal priority
    Lowest -> Gives thread lowest priority
    Highest -> Gives thread highest priority
    
    so you would probably use:
    
    Thread1.Priority=System.Threading.ThreadPriority.BelowNormal
    
        3
  •  0
  •   Larry Hipp    16 年前

    你的imagescalled()是如何将图像复制回用户界面的?

        4
  •  0
  •   Mike Dinescu    16 年前

    试着用这个来代替。

    Private Sub Worker(object o)
        Dim args as ScaleImageArguments
        args = CType(o, ScaleImageArguments) 
        ScaleImage(args)
    End Sub
    
    Private Sub RunScaleImageAsync(ByVal img As Image, ByVal scale As Double)
        System.Threading.ThreadPool.QueueUserWorkItem(Worker, _
                     New ScaleImageArguments(img.Clone, scale))
    End Sub
    

    替代方案 -使用异步模式。

    Private Delegate Sub ScaleImageDelegate(ByRef arg As ScaleImageArguments)
    
    Private Sub BeginScaleImage(ByRef img As Image, ByVal scale As Double)
        Dim d As ScaleImageDelegate
        d = New ScaleImageDelegate(AddressOf ScaleImage)
    
        d.BeginInvoke(New ScaleImageArguments(img.Clone, scale), _
                      New AsyncCallback(AddressOf EndScaleImage), d)        
    End Sub
    
    Private Sub EndScaleImage(ar As IAsyncResult)
        Dim d As ScaleImageDelegate
        d = CType(ar.AsyncState, ScaleImageDelegate)
        d.EndInvoke(ar)
    End Sub
    

    然后调用beginscaleImage异步运行它。

    编辑 -请参阅上面的更正。endscaleImage上的ar参数应声明为byRef,并且还应声明beginscaleImage的img参数。没有理由让他们过关!!