【问题标题】:CRITICAL_SECTION occurs deadlock when using DuplicateOutput使用 DuplicateOutput 时 CRITICAL_SECTION 发生死锁
【发布时间】:2015-10-17 05:46:12
【问题描述】:

我正在使用 IDXGIOutputDuplication 编写 C++/CLI 程序。

我想从多个线程中获取图像,所以我使用了 CriticalSection。但是,包含“AcquireNextFrame()”和“ReleaseFrame()”的代码,线程死锁了。

如果 UpdateDesktopImage() 从程序中删除,将不会发生死锁。这些函数从 .NET Framework 线程 (System.Threading.Thread) 调用。我想知道这个原因和解决方法。

HRESULT DesktopDupli::Initialize(int dispno, IDXGIAdapter *adapter, IDXGIOutput *output)
{
    HRESULT hr = S_OK;

    IDXGIOutput1 *dxgi_op1 = NULL;

    DXGI_OUTPUT_DESC desc_op;
    hr = output->GetDesc(&desc_op);
    sw = desc_op.DesktopCoordinates.right - desc_op.DesktopCoordinates.left;
    sh = desc_op.DesktopCoordinates.bottom - desc_op.DesktopCoordinates.top;

    D3D_FEATURE_LEVEL FeatureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_1
    };
    D3D_FEATURE_LEVEL level;
    UINT levels = ARRAYSIZE(FeatureLevels);

    hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN,
        NULL, 0, FeatureLevels, levels,
        D3D11_SDK_VERSION, &device, &level, &context);
    if (FAILED(hr)) goto EXIT;

    hr = output->QueryInterface(__uuidof(IDXGIOutput1), (void**)&dxgi_op1);
    if (FAILED(hr)) goto EXIT;

    hr = dxgi_op1->DuplicateOutput(device, &dupli);
    if (FAILED(hr)) goto EXIT;

    this->dispno = dispno;

    pixelbufLen = sh * sw * 4;
    pixelbuf1 = new BYTE[pixelbufLen];

EXIT:
    RELEASE(dxgi_op1);

    return hr;
}

void DesktopDupli::Remove()
{
    EnterCriticalSection(&csec);

    // delete some buffer
    if (pixelbuf){
        delete[]pixelbuf;
        pixelbuf = NULL;
    }

    LeaveCriticalSection(&csec);
}

HRESULT DesktopDupli::UpdateDesktopImage()
{
    EnterCriticalSection(&csec);

    HRESULT hr = S_OK;
    IDXGIResource* res = NULL;
    ID3D11Texture2D *deskimage = NULL;

    DWORD c = GetTickCount();
    if (c >= lastUpdate && c < lastUpdate + 10) goto EXIT;
    lastUpdate = c;

    if (!dupli/*<-IDXGIOutputDuplication */) {
        hr = E_POINTER;
        goto EXIT;
    }

    dupli->ReleaseFrame();
    if (FAILED(hr)) goto EXIT;
    hr = dupli->AcquireNextFrame(500, &frameinfo, &res);
    if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
        hr = S_OK;
        goto EXIT;
    } else if (FAILED(hr)){
        goto EXIT;
    }

    hr = res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&deskimage);
    if (FAILED(hr)) goto EXIT;
    if (frameinfo.AccumulatedFrames == 0) {
        dupli->ReleaseFrame();
    }else {
        hr = SetPixel(deskimage); //CopySubresourceRegion
    }

EXIT:
    RELEASE(deskimage);
    RELEASE(res);

    LeaveCriticalSection(&csec);
    return hr;
}

【问题讨论】:

  • 如果只有这两个函数使用 csec 作为锁定对象,那么我怀疑 UpdateDesktopImage 调用 Remove 某处(ReleaseFrame?)导致问题
  • 你能用调试器看到死锁的地方吗?
  • @o_weisman:线程一旦获得锁,就可以多次进入临界区锁。一旦线程获得了锁,对 EnterCriticalSection() 的后续调用就会成功而不会阻塞。必须平衡对 EnterCriticalSection() 和 LeaveCriticalSection() 的调用,以确保线程放弃锁定。所示代码中可能发生死锁的唯一方法是,如果在单独的线程中调用这两个函数,其中 UpdateDesktopImage() 具有锁并执行等待 Remove() 线程的操作,该线程正在等待 UpdateDesktopImage()释放锁。

标签: c++ multithreading winapi directx-11 critical-section


【解决方案1】:

在:

hr = res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&deskimage);
    if (FAILED(hr)) goto EXIT;

你忘记在EXIT之前dupli-&gt;ReleaseFrame()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-03
    • 2015-09-22
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    相关资源
    最近更新 更多