WriteableBitmap死锁

时间:2014-03-05 23:53:49

标签: c# deadlock writeablebitmap

我正在使用WriteableBitmap实现流式视频的视频显示(需要每秒重新写入30次) 屏幕上有几个,每个都有自己的视频要显示。
视频也需要解码,所以我使用工作线程(每个位图一个)进行解码并写入BackBuffer,然后使用UI线程锁定AddDirtyRect并解锁,如此

m_WrtblBtmp.Dispatcher.Invoke(() =>
{
    Debug.WriteLine("About to lock Bitmap" + m_WrtblBtmp.GetHashCode().ToString());
    m_WrtblBtmp.Lock();                     
});


if (ReadNextVideoFrame(m_VideoDecoder, m_BackBuffer))
{
    m_WrtblBtmp.Dispatcher.Invoke(() => 
    {
        Debug.WriteLine("About to dirty up Bitmap" + m_WrtblBtmp.GetHashCode().ToString());
        m_WrtblBtmp.AddDirtyRect(new Int32Rect(0, 0, 1280, 1024));
    });
}

m_WrtblBtmp.Dispatcher.Invoke(() => 
{
    Debug.WriteLine("About to Unlock Bitmap" + m_WrtblBtmp.GetHashCode().ToString());
    m_WrtblBtmp.Unlock();
});

ReadNextVideoFrame通过m_BackBuffer指针(WriteableBitmap.BackBuffer的副本)获取,解码并将视频帧写入位图 我遇到的问题是,一旦你有足够的线程,这件事就会陷入僵局。没有Thread.Sleep我可以很快地在2个线程上死锁。通过一点点睡眠它可以通过,但添加更多线程会带来问题,我只能在视频速度降低到低于实时速度之前睡得那么多(它必须是实时的)。

据说微软鼓励这种做法 http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.lock(v=vs.110).aspx
我发现了一个错误吗?

如果我通过WritePixels写入前端缓冲区没有死锁,但为此我需要再复制一次数据并在WritePixels期间占用GUI线程,所以如果可以,我宁愿使用BackBuffer

这是运行2个线程时Debug.WriteLine的输出:
About to lock Bitmap53653601 About to lock Bitmap31265986 About to dirty up Bitmap53653601 About to dirty up Bitmap31265986 About to Unlock Bitmap53653601 About to Unlock Bitmap31265986 ... more of the same ... About to dirty up Bitmap50546581 About to Unlock Bitmap50546581 About to dirty up Bitmap9315575 About to lock Bitmap50546581 About to Unlock Bitmap9315575 About to lock Bitmap9315575 About to dirty up Bitmap50546581 About to Unlock Bitmap50546581 About to dirty up Bitmap9315575 About to lock Bitmap50546581 ... then nothing (deadlock) ...

1 个答案:

答案 0 :(得分:0)

您链接的页面也说明了这一点:

  

当渲染线程获取后缓冲区上的锁以复制它时,UI线程可以阻止   转发到前台缓冲区。如果此块的延迟太长,请使用TryLock方法   等待很短的时间,然后解锁UI线程以执行其他任务,而后缓冲区>锁住了。

所以我假设你的一个线程卡在那个锁中,就像他们说的那样。也许是这样的?

while (SomethingIsTrue) // i'm presuming you have a loop like this already?)
{
    bool gotLock = false;

    m_WrtblBtmp.Dispatcher.Invoke(() =>
    {
        Debug.WriteLine("About to try to lock Bitmap" + m_WrtblBtmp.GetHashCode().ToString());
        gotLock = m_WrtblBtmp.TryLock(SomeTimeoutConstant);                     
        Debug.WriteLine((gotLock ? "got lock on " : "DID NOT lock ") + m_WrtblBtmp.GetHashCode().ToString());

    });

    if (gotLock && ReadNextVideoFrame(m_VideoDecoder, m_BackBuffer))
    {
        m_WrtblBtmp.Dispatcher.Invoke(() => 
        {
            Debug.WriteLine("About to dirty up Bitmap" + m_WrtblBtmp.GetHashCode().ToString());
            m_WrtblBtmp.AddDirtyRect(new Int32Rect(0, 0, 1280, 1024));
            Debug.WriteLine("About to Unlock Bitmap" + m_WrtblBtmp.GetHashCode().ToString());
            m_WrtblBtmp.Unlock();
        });
    }

}