0
我正在用IDXGIOutputDuplication編寫C++/CLI程序。使用DuplicateOutput時CRITICAL_SECTION發生死鎖
我想從多個線程獲取圖像,所以我使用了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;
}
忘記
dupli->ReleaseFrame()
如果這是在您使用商業性剝削爲您鎖定的對象只有兩個功能,那麼我懷疑UpdateDesktopImage要求刪除某個地方(ReleaseFrame ?)導致問題 –你能看到它使用調試器死鎖的位置嗎? –
@ o_weisman:一旦線程獲得鎖定,就允許線程多次輸入關鍵部分鎖。線程一旦鎖定後,對EnterCriticalSection()的後續調用就會成功並且不會被阻塞。必須平衡對EnterCriticalSection()和LeaveCriticalSection()的調用,以確保線程放棄鎖定。在顯示的代碼中發生死鎖的唯一方法是兩個函數是否在單獨的線程中調用,其中UpdateDesktopImage()具有鎖並執行等待UpdateDesktopImage()的Remove()線程以等待釋放鎖。 –