<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,comments - 227,trackbacks - 0

    現象

    用多線程方法設計socket程序時,你會發現在跨線程使用CAsyncSocket及其派生類時,會出現程序崩潰。所謂跨線程,是指該對象在一個線程中 調用Create/AttachHandle/Attach函數,然后在另外一個線程中調用其他成員函數。下面的例子就是一個典型的導致崩潰的過程:
    CAsyncSocket Socket;
    UINT Thread(LPVOID)
    {
    Socket.Close ();
    return 0;
    }
    void CTestSDlg::OnOK()
    {
    // TODO: Add extra validation here
    Socket.Create(0);
    AfxBeginThread(Thread,0,0,0,0,0);
    }

    其中Socket對象在主線程中被調用,在子線程中被關閉。

    跟蹤分析

    這個問題的原因可以通過單步跟蹤(F11)的方法來了解。我們在Socket.Create(0)處設斷點,跟蹤進去會發現下面的函數被調用:

    void PASCAL CAsyncSocket::AttachHandle(
    SOCKET hSocket, CAsyncSocket* pSocket, BOOL bDead)
    {
    _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
    BOOL bEnable = AfxEnableMemoryTracking(FALSE);
    if (!bDead)
    {
    ASSERT(CAsyncSocket::LookupHandle(hSocket, bDead) == NULL);
    if (pState->m_pmapSocketHandle->IsEmpty())
    {
    ASSERT(pState->m_pmapDeadSockets->IsEmpty());
    ASSERT(pState->m_hSocketWindow == NULL);
    CSocketWnd* pWnd = new CSocketWnd;
    pWnd->m_hWnd = NULL;
    if (!pWnd->CreateEx(0, AfxRegisterWndClass(0),
    _T("Socket Notification Sink"),
    WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL))
    {
    TRACE0("Warning: unable to create socket notify window!"n");
    AfxThrowResourceException();
    }
    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
    {
    int nCount;
    if (pState->m_pmapDeadSockets->Lookup((void*)hSocket, (void*&)nCount))
    nCount++;
    else
    nCount = 1;
    pState->m_pmapDeadSockets->SetAt((void*)hSocket, (void*)nCount);
    }
    AfxEnableMemoryTracking(bEnable);
    }

    在這個函數的開頭,首先獲得了一個pState的指針指向_afxSockThreadState對象。從名字可以看出,這似乎是一個和線程相關的變量,實際上它是一個宏,定義如下:

    #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)
    {
    ASSERT(CAsyncSocket::LookupHandle(hSocket, FALSE) != NULL);

    我們在這個ASSERT處設置斷點,跟蹤進LookupHandle,會發現這個函數定義如下:

    CAsyncSocket* PASCAL CAsyncSocket::LookupHandle(SOCKET hSocket, BOOL bDead)
    {
    CAsyncSocket* pSocket;
    _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
    if (!bDead)
    {
    pSocket = (CAsyncSocket*)
    pState->m_pmapSocketHandle->GetValueAt((void*)hSocket);
    if (pSocket != NULL)
    return pSocket;
    }
    else
    {
    pSocket = (CAsyncSocket*)
    pState->m_pmapDeadSockets->GetValueAt((void*)hSocket);
    if (pSocket != NULL)
    return pSocket;
    }
    return NULL;
    }

    顯然,這個函數試圖從當前線程查詢關于這個 socket的信息,可是這個信息放在創建這個socket的線程中,因此這種查詢顯然會失敗,最終返回NULL。

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

    如何在多線程之間傳遞socket

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

    1. 當前擁有這個socket的線程調用Detach方法,這樣socket句柄和C++對象及當前線程脫離關系
    2. 當前線程把這個對象傳遞給另外一個線程
    3. 另外一個線程創建新的CAsyncSocket對象,并調用Attach

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

    CAsyncSocket Socket;
    UINT Thread(LPVOID sock)
    {
    Socket.Attach((SOCKET)sock);
    Socket.Close ();
    return 0;
    }
    void CTestSDlg::OnOK()
    {
    // TODO: Add extra validation here
    Socket.Create(0);
    SOCKET hSocket = Socket.Detach ();
    AfxBeginThread(Thread,(LPVOID)hSocket,0,0,0,0);
    }
    posted on 2008-07-03 15:22 SIMONE 閱讀(837) 評論(0)  編輯  收藏 所屬分類: C++
    主站蜘蛛池模板: 免费在线观看你懂的| 99免费在线观看视频| 成全视频在线观看免费高清动漫视频下载| 亚洲国产精品无码成人片久久| 一级做α爱过程免费视频| 全部免费a级毛片| 国产精品亚洲а∨无码播放麻豆| 国产美女a做受大片免费| 亚洲欧洲精品成人久久曰| 性色av免费观看| 亚洲heyzo专区无码综合| 日韩激情淫片免费看| 国产精品亚洲精品日韩动图| 免费人成在线观看网站视频| 一个人晚上在线观看的免费视频 | 毛片在线免费视频| 100部毛片免费全部播放完整| 久久精品夜色国产亚洲av| 野花香高清视频在线观看免费| 久久夜色精品国产亚洲| 亚洲欧洲免费视频| 亚洲国产美女精品久久久久| 午夜免费福利影院| 人人公开免费超级碰碰碰视频| 亚洲乱码中文字幕综合| 久久久久国产精品免费看 | 亚洲另类自拍丝袜第1页| 国产免费的野战视频| 亚洲av无码专区在线电影天堂| 四虎精品亚洲一区二区三区| 成人电影在线免费观看| 亚洲午夜精品国产电影在线观看| 久久这里只有精品国产免费10| 粉色视频在线观看www免费| 最新亚洲成av人免费看| 久久精品一本到99热免费| 亚洲色大18成人网站WWW在线播放| 国产免费人成视频在线观看| 一个人免费观看www视频| 亚洲欧洲国产成人精品| 国产yw855.c免费视频|