今天編譯了一段程序,運行的時候崩潰了,下斷點查看了下崩潰的地方,發現問題出在使用傳指針方式向線程傳遞局部變量。問題代碼大致如下:
void CStrLenCheckDlg::OnOK()
{
THREADINFO info; // 局部變量
info.pDlg = this;
info.strFileName = m_strFileName;
// 以傳指針方式傳遞局部變量 info 給線程函數
AfxBeginThread(ThreadFunc, &info);
}
UINT ThreadFunc(LPVOID lpParam)
{
THREADINFO* pInfo = (THREADINFO*)lpParam;
if (NULL != pInfo && NULL != pInfo->pDlg)
{
pInfo->pDlg->CheckPath(pInfo->strFileName);
// 崩潰語句,pInfo->pDlg 的內存地址與原來不同
pInfo->pDlg->GetDlgItem(IDOK)->EnableWindow(FALSE);
}
return 0;
}
當 AfxBeginThread() 執行結束后,主線程從 CStrLenCheckDlg::OnOK() 函數返回。但是,新創建的線程的線程函數 ThreadFunc() 仍就在執行中,此時問題就出來了。向線程函數 ThreadFunc() 傳遞的參數 info 是在 CStrLenCheckDlg::OnOK() 中定義的局部變量,當 CStrLenCheckDlg::OnOK() 返回時,局部變量 info 的內存中已經被釋放。此時,ThreadFunc() 讀取了一段被釋放的內存,勢必出現問題。
解決方法有二:一個是 new 出一個 info 變量,然后由線程函數 ThreadFunc() 負責 delete 掉;另一個是將 info 變量傳入后立即在線程函數 ThreadFunc() 中拷貝一份副本。
方法一:
void CStrLenCheckDlg::OnOK()
{
THREADINFO* pInfo = new THREADINFO;
pInfo->pDlg = this;
pInfo->strFileName = m_strFileName;
AfxBeginThread(ThreadFunc, pInfo);
}
UINT ThreadFunc(LPVOID lpParam)
{
THREADINFO* pInfo = (THREADINFO*)lpParam;
if (NULL != pInfo && NULL != pInfo->pDlg)
{
pInfo->pDlg->CheckPath(pInfo->strFileName);
pInfo->pDlg->GetDlgItem(IDOK)->EnableWindow(FALSE);
}
delete pInfo;
return 0;
}
方法二:
void CStrLenCheckDlg::OnOK()
{
THREADINFO info; // 局部變量
info.pDlg = this;
info.strFileName = m_strFileName;
// 以傳指針方式傳遞局部變量
AfxBeginThread(ThreadFunc, &info);
}
UINT ThreadFunc(LPVOID lpParam)
{
if (NULL != lpParam)
{
THREADINFO info = *((THREADINFO*)lpParam);
if (NULL != info.pDlg)
{
info.pDlg->CheckPath(info.strFileName);
info.pDlg->GetDlgItem(IDOK)->EnableWindow(FALSE);
}
}
return 0;
}
方法二中代碼不能保證在拷貝副本的時候 CStrLenCheckDlg::OnOK() 函數未返回,為了萬無一失可以使用信號量來做延遲。