我正在MFC中使用後臺工作線程(通過_beginthreadex
創建)和UI線程編寫應用程序。從UI線程中單擊一個按鈕以開始和結束工作線程。如果m_threadRunning
標誌爲false,它將啓動後臺線程,如果它爲true,則停止後臺線程。我關於停止線程的方式是將m_threadRunning
標誌設置爲false,並調用WaitForSingleObject
讓後臺線程完成正在執行的操作。MFC應用程序掛起線程發信號通知終止
我的應用程序有四種不同的狀態。我有前三個州正常工作,添加第四個州是什麼導致我的問題。對於第四個狀態,我希望能夠對桌面進行採樣並將平均RGB值發送到COM端口進行處理。當處於前三種狀態時,如果我想停止向COM端口發送數據的執行,它將正常終止並且沒有問題。如果我處於第四狀態並單擊「停止」,則應用程序將掛起,因爲我沒有時間撥打WaitForSingleObject
。
我也有一個自定義CEdit
框CColorEdit
,它顯示當前的RGB值。當我處於狀態3或4時,我會從後臺線程更新它(因爲它們都動態地更改顏色)。當我將顏色設置爲Invalidate
或RedrawWindow
時,我已將問題範圍縮小至打電話。
我已經想出了一些解決方案,但我不喜歡它們中的任何一個,並且寧可理解是什麼導致了這個問題,因爲我在MFC中編寫這個目標的目的是學習和理解MFC。這是什麼已經解決了這個問題:
- 我在我的工作線程中調用睡眠()已經在約60採樣/秒。將其更改爲較低的值(例如每秒30個採樣點),大多數時間都解決了問題。
- 我在我的工作線程中輪詢
m_threadRunning
以檢查線程是否應該終止。如果我在對屏幕進行採樣後但在更新編輯控件之前對其進行輪詢,則可以在大多數情況下解決問題。 - 我在調用
WaitForSingleObject
時做了5秒的超時,並且在線程無法等待時調用TerminateThread手動終止該線程,這樣可以一直解決問題。這是我現在的解決方案。
下面是相關的代碼位(我鎖周圍的任何使用outBytes的):
void CLightControlDlg::UpdateOutputLabel()
{
CSingleLock locker(&m_crit);
locker.Lock();
m_outLabel.SetColor(outBytes[1], outBytes[2], outBytes[3]); //the call to this freezes the program
CString str;
str.Format(L"R = %d; G = %d; B = %d;", outBytes[1], outBytes[2], outBytes[3]);
m_outLabel.SetWindowText(str);
}
這部分代碼是用於終止工作線程
m_threadRunning = false;
locker.Unlock(); //release the lock...
//omitted re-enabling of some controls
//normally this is just WaitForSingleObject(m_threadHand, INFINITE);
if(WaitForSingleObject(m_threadHand, 5000) == WAIT_TIMEOUT)
{
MessageBox(L"There was an error cancelling the I/O operation to the COM port. Forcing a close.");
TerminateThread(m_threadHand, 0);
}
CloseHandle(m_threadHand);
CloseHandle(m_comPort);
m_threadHand = INVALID_HANDLE_VALUE;
m_comPort = INVALID_HANDLE_VALUE;
的代碼在我派生編輯控件,更新文本顏色:
void SetColor(byte r, byte g, byte b)
{
_r = r;
_g = g;
_b = b;
br.DeleteObject();
br.CreateSolidBrush(RGB(r,g,b));
Invalidate(); //RedrawWindow() freezes as well
}
最後,我的線程程序的代碼:
unsigned int __stdcall SendToComProc(void * param)
{
CLightControlDlg *dlg = (CLightControlDlg*)param;
while(1)
{
if(!dlg->IsThreadRunning())
break;
switch(dlg->GetCurrentState())
{
case TransitionColor: //state 3
dlg->DoTransition();
dlg->UpdateOutputLabel();
break;
case ScreenColor: //state 4
dlg->DoGetScreenAverages();
//if(!dlg->IsThreadRunning()) break; //second poll to IsThreadRunning()
dlg->UpdateOutputLabel();
break;
}
dlg->SendToCom();
Sleep(17); // Sleep for 1020/60 = 17 = ~60samples/sec
}
return 0;
}
任何幫助,您可以提供非常感謝!
謝謝!我認爲這可能是這樣的,我熟悉調用Invoke on控件的C#方法,但甚至沒有想到它的MFC。 –