CAsyncSocket物件不能跨執行緒之分析

2021-06-16 03:52:46 字數 1992 閱讀 6628

原文:

用多執行緒方法設計socket程式時,你會發現在跨執行緒使用casyncsocket及其派生類時,會出現程式崩潰。所謂跨執行緒,是指該物件在乙個執行緒中呼叫create/attachhandle/attach函式,然後在另外乙個執行緒中呼叫其他成員函式。下面的例子就是乙個典型的導致崩潰的過程:

casyncsocket socket;

uint thread(lpvoid)

void ctestsdlg::onok()

其中socket物件在主線程中被呼叫,在子執行緒中被關閉。

這個問題的原因可以通過單步跟蹤(f11)的方法來了解。我們在socket.create(0)處設斷點,跟蹤進去會發現下面的函式被呼叫:

void pascal casyncsocket::attachhandle(

socket hsocket, casyncsocket* psocket, bool bdead)

assert(pwnd->m_hwnd != null);

assert(cwnd::fromhandlepermanent(pwnd->m_hwnd) == pwnd);

pstate->m_hsocketwindow = pwnd->m_hwnd;

}pstate->m_pmapsockethandle->setat((void*)hsocket, psocket);

}else

afxenablememorytracking(benable);

}

#define _afxsockthreadstate afxgetmodulethreadstate()
我們沒有必要去細究這個指標的定義是如何的,只要知道它是和當前執行緒密切關聯的,其他執行緒應該也有類似的指標,只是指向不同的結構。

在這個函式中,casyncsocket建立了乙個視窗,並把如下兩個資訊加入到pstate所管理的結構中:

pstate->m_pmapsockethandle->setat((void*)hsocket, psocket);

pstate->m_pmapdeadsockets->setat((void*)hsocket, (void*)ncount);

pstate->m_hsocketwindow = pwnd->m_hwnd;

pstate->m_pmapsockethandle->setat((void*)hsocket, psocket);

當呼叫close時,我們再次跟蹤,就會發現在killsocket中,下面的函式出現錯誤:

void pascal casyncsocket::killsocket(socket hsocket, casyncsocket* psocket)

else

return null;

}

顯然,這個函式試圖從當前執行緒查詢關於這個 socket的資訊,可是這個資訊放在建立這個socket的執行緒中,因此這種查詢顯然會失敗,最終返回null。

有人會問,既然它是assert出錯,是不是release就沒問題了。這只是自欺欺人。assert/verify都是檢驗一些程式正常執行必須正確的條件。如果assert都失敗,在release中也許不會顯現,但是你的程式肯定執行不正確,啥時候出錯就不知道了。

有些特殊情況下,可能需要在不同執行緒之間傳遞socket。當然我不建議在使用casyncsocket的時候這麼做,因為這增加了出錯的風險(尤其當出現拆解包問題時,有人稱為粘包,我基本不認同這種稱呼)。如果一定要這麼做,方法應該是:

當前擁有這個socket的執行緒呼叫detach方法,這樣socket控制代碼和c++物件及當前執行緒脫離關係

當前執行緒把這個物件傳遞給另外乙個執行緒

另外乙個執行緒建立新的casyncsocket物件,並呼叫attach

上面的例子,我稍微做修改,就不會出錯了:

casyncsocket socket;

uint thread(lpvoid sock)

void ctestsdlg::onok()

CAsyncSocket物件不能跨執行緒之分析

casyncsocket物件不能跨執行緒之分析 用多執行緒方法設計socket程式時,你會發現在跨執行緒使用casyncsocket及其派生類時,會出現程式崩潰。所謂跨執行緒,是指該物件在乙個執行緒中呼叫create attachhandle attach函式,然後在另外乙個執行緒中呼叫其他成員函式...

CAsyncSocket物件不能跨執行緒之分析

用多執行緒方法設計socket程式時,你會發現在跨執行緒使用casyncsocket及其派生類時,會出現程式崩潰。所謂跨執行緒,是指該物件在乙個執行緒中呼叫create attachhandle attach函式,然後在另外乙個執行緒中呼叫其他成員函式。下面的例子就是乙個典型的導致崩潰的過程 cas...

CAsyncSocket程式設計 MFC

許多時候我們實現網路程式設計使用的是winsock api函式,雖然這些函式使用起來也很方便,很靈活,但是vc 的mfc類庫中提供了casyncsocket這樣乙個套接字類,用它來實現socket程式設計會更方便。server端的程式設計與client端的類似,下面主要介紹他的listen及acce...