UC故事2011/12/03 - 1 线程相关的东东


1.  CThreadManager::InitMain()

最终的create动作,则CRtThread::Create来完成;

若是TT_MAIN,则并未做线程生成工作,只是做了一些registration的工作(如把当前thread register到CThreadManager的唯一实例中。


* STACK TRACE for Win32 Main Thread 

CRtReactorWin32Message:: Open() line 176
CRtThreadReactor:: Create(int 0, CRtThreadManager::TFlag TF_JOINABLE) line 40 + 19 bytes
CRtThreadManager::CreateReactorThread(int 0, IRtReactor * 0x020879c8, CRtThread * & 0x00000000) line 368 + 41 bytes
CRtThreadManager::InitMainThread(int 0, char * * 0x00000000) line 191 + 24 bytes
CRtThreadManager::Instance() line 132 + 15 bytes
RtCoInitialize() line 179 + 5 bytes
ILDebugStart(unsigned short 33201, void * 0x00000001) line 1482
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f28, int 1) line 83 + 8 bytes
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! 7c817077()

* CODE 

RtResult CRtThreadReactor::
Create(CRtThreadManager::TType aType, CRtThreadManager::TFlag aFlag)
{
RtResult rv = CRtThread::Create(aType, aFlag);
if (RT_SUCCEEDED(rv)) {
// have to open reactor here because main function will do some initial stuffs.
if (m_Type == CRtThreadManager::TT_MAIN) {
rv = m_pReactor-> Open();                    // 在此处注册了主线程的主窗口的Windows Class,并生成了主窗口实例,但并没有使用Asyncselect与任何socket绑定
if (RT_FAILED(rv)) {
RT_ERROR_TRACE("CRtThreadReactor::OnThreadRun, m_pReactor->Open() failed! rv=" << rv);
}
}
}
return rv;
}

Q:没有使用WSAAsyncselect的原因是:因为这是一个主线程,不需要和socket发生关系?因为这是为Windows Server写的代码?如果是Windows Client,则实际上这些代码没有意义了,因为在Windows Client中,事件循环实际上是Windows的Message Loop,由WTL的MessageLoop.run()控制?

Q:open()中的定时器设置是何目的?

Q:是否在Windows Client的程序中,这些代码实际无用?但为什么又执行了?


5. 网络线程生成:在CRtThreadManager::InitMainThread()中调用

* STACK TRACE

CRtReactorWin32Message::Open() line 166                                                // 这里完成窗口类注册,窗口生成等等
CRtThreadReactor::OnThreadInit() line 54 + 19 bytes
CRtThread::ThreadProc(void * 0x02087e50) line 144 + 13 bytes
_threadstartex(void * 0x02087f00) line 227 + 13 bytes
KERNEL32! 7c80b729()


Q:在哪里调用的OnHandleRegiester去设置网络事件?


* 设断点跟踪

STACK TRACE如下:

CRtReactorWin32AsyncSelect:: OnHandleRegister(void * 0x00000650, long 2, IRtEventHandler * 0x0208b2a8) line 343
CRtReactorBase::RegisterHandler(IRtEventHandler * 0x0208b2a8, long 2) line 219 + 31 bytes
CRtConnectorTcpT<CRtConnectorWrapper,CRtTransportTcp,CRtSocketStream>::Connect_i(CRtTransportTcp * 0x0208b640, const CRtInetAddr & {...}) line 202 + 25 bytes
CRtConnectorTcpT<CRtConnectorWrapper,CRtTransportTcp,CRtSocketStream>::Connect(const CRtInetAddr & {...}, CRtInetAddr * 0x00000000) line 82 + 22 bytes
CRtConnectorWrapper::AsycConnect(IRtAcceptorConnectorSink * 0x0208b500, const CRtInetAddr & {...}, CRtTimeValue * 0x0208d37c, CRtInetAddr * 0x00000000) line 109 + 26 bytes
CConnConnectorT<CRtConnRlbTcpClient>::AsycConnect(IRtAcceptorConnectorSink * 0x0208cfd4, const CRtInetAddr & {...}, CRtTimeValue * 0x0208d37c, CRtInetAddr * 0x00000000) line 357 + 84 bytes
CEventAsycConnect::OnEventFire() line 187 + 74 bytes
CRtEventQueueBase::ProcessOneEvent(IRtEvent * 0x0208d350) line 229 + 12 bytes
CRtEventQueueBase::ProcessEvents(const std::list<IRtEvent *,std::allocator<IRtEvent *> > & {...}) line 217
CRtReactorBase::ProcessHandleEvent(void * 0xffffffff, long 256, int 0, int 1, int 0) line 324 + 18 bytes
CRtReactorWin32Message::Win32SocketWndProc(HWND__ * 0x00130c8c, unsigned int 1058, unsigned int 4294967295, long 256) line 115
USER32! 77d18734()
USER32! 77d18816()
USER32! 77d189cd()
USER32! 77d196c7()
CRtReactorWin32Message::RunEventLoop() line 262 + 15 bytes
CRtThreadReactor::OnThreadRun() line 67 + 19 bytes
CRtThread::ThreadProc(void * 0x02087e50) line 151 + 13 bytes
_threadstartex(void * 0x02087f00) line 227 + 13 bytes
KERNEL32! 7c80b729()

注1:是在第三个线程中出现的这个执行序列,why第三个线程?

注2:Win32Message::Win32SocketWndProc是从WM_WIN32_SOCKET_NOTIFY分支进入

case WM_WIN32_SOCKET_NOTIFY:
{
CRtReactorWin32Message *pReactor = (CRtReactorWin32Message *)::GetWindowLong(hwnd, 0);
RT_HANDLE fdOn = (RT_HANDLE)wParam;
IRtEventHandler::MASK maskEh = (IRtEventHandler::MASK)lParam;
RT_ASSERTE(pReactor);
pReactor->ProcessHandleEvent(fdOn, maskEh, RT_OK, TRUE);
#ifndef RT_ENABLE_CALENDAR_TIMER
pReactor->ProcessTimerTick();
#endif // !RT_ENABLE_CALENDAR_TIMER
return 0;
}

Q:谁发送了这条消息?为什么这条消息最终解释成为一个CEventAsycConnect事件?

    A:经查,在NotifyHandler中发的消息。


* 再设断点跟踪

STACK TRACE:

CRtReactorWin32Message::NotifyHandler(IRtEventHandler * 0x00000000, long 256) line 236
CRtReactorBase::PostEvent(IRtEvent * 0x0208d350, IRtEventQueue::EPriority EPRIORITY_NORMAL) line 519 + 20 bytes
CRtConnectorThreadProxy::AsycConnect(IRtAcceptorConnectorSink * 0x0208d048, const CRtInetAddr & {...}, CRtTimeValue * 0x0208cf20, CRtInetAddr * 0x00000000) line 105 + 59 bytes
CRtDetectionConnector::CConnectorItem::AsycConnect(CRtTimeValue * 0x0208cf20, CRtInetAddr * 0x00000000) line 214 + 46 bytes
CRtDetectionConnector::StartDetectionConnect(IRtAcceptorConnectorSink * 0x0208d280, CRtTimeValue * 0x0012c304, IRtDetectionConnector::DetectMode DETECT_INTERVAL_1S, CRtInetAddr * 0x00000000) line 78
CRtIMConnProvider::Connect_i(IConnProviderSink * 0x0208cab8, unsigned long 1, const TransportAddress * 0x0208ccb8, Event_Type EVENT_TYPE_CONFERENCE_PING, CRtTimeValue * 0x0012c304, int 0, int 1) line 454 + 39 bytes
CRtIMConnProvider::Connect(IConnProviderSink * 0x0208cab8, unsigned long 1, const TransportAddress * 0x0208ccb8, Event_Type EVENT_TYPE_CONFERENCE_PING, CRtTimeValue * 0x0012c304, int 0) line 356
CPingBase::Ping() line 116 + 51 bytes
CPingBase::StartPing() line 93
CConference::JoinConference(const CConfDetailInfo & {...}, const CInfoRosterInfo & {...}, unsigned short 1, const CRtString * 0x0208954c {0x020899c9 "tcp://192.168.1.100:443"}, int 0, unsigned long 2147483648) line 225 + 24 bytes
CConfManage::CreateConference() line 2617 + 103 bytes
CMainFrame::OnCreate(unsigned int 1, unsigned int 1, unsigned int 1, unsigned int 1) line 1879
CMainFrame::ProcessWindowMessage(HWND__ * 0x00040e4e, unsigned int 1, unsigned int 0, long 1269856, long & -858993460, unsigned long 0) line 138 + 37 bytes
ATL::CWindowImplBaseT<ATL::CWindow,ATL::CWinTraits<114229248,262400> >::WindowProc(HWND__ * 0x02088920, unsigned int 1, unsigned int 0, long 1269856) line 2110 + 37 bytes
USER32! 77d18734()
USER32! 77d2bdf1()
USER32! 77d28ea0()
USER32! 77d2ce7c()
NTDLL! 7c92e473()
USER32! 77d2e442()
USER32! 77d2e4dc()
WTL::CFrameWindowImplBase<ATL::CWindow,ATL::CWinTraits<114229248,262400> >::Create(HWND__ * 0x00000000, ATL::_U_RECT {...}, const char * 0x001366e0, unsigned long 114229248, unsigned long 262400, ATL::_U_MENUorID {...}, unsigned short 50047, void * 0x00000000) line 456 + 91 bytes
WTL::CFrameWindowImpl<CMainFrame,ATL::CWindow,ATL::CWinTraits<114229248,262400> >::Create(HWND__ * 0x00000000, ATL::_U_RECT {...}, const char * 0x001366e0, unsigned long 114229248, unsigned long 262400, HMENU__ * 0x19400cd9, void * 0x00000000) line 1196
WTL::CFrameWindowImpl<CMainFrame,ATL::CWindow,ATL::CWinTraits<114229248,262400> >::CreateEx(HWND__ * 0x00000000, ATL::_U_RECT {...}, unsigned long 0, unsigned long 0, void * 0x00000000) line 1221 + 42 bytes
Run(char * 0x00151f28, int 1) line 195 + 35 bytes
LaunchConf(HINSTANCE__ * 0x00400000, char * 0x00151f28, int 1) line 318 + 13 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f28, int 1) line 85 + 20 bytes
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! 7c817077()


注1:是界面线程在初始化过程中,create conference触发的。

Q:如何找到这个网络线程的windows handle的?


* 其它线程对网络线程的访问:



CRtConnectorThreadProxy::
CRtConnectorThreadProxy(CRtConnectionManager::CType aType, 
CRtThread *aThreadNetwork,
CRtThread *aThreadUser)
: CRtAcceptorConnectorSinkThreadProxyT<CRtConnectorThreadProxy>(this)
, m_pThreadUser(aThreadUser)
, m_pThreadNetwork(aThreadNetwork)
, m_Type(aType)
{
if (!m_pThreadNetwork) {
m_pThreadNetwork= CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_NETWORK);
RT_ASSERTE(m_pThreadNetwork);
}
if (!m_pThreadUser) {
m_pThreadUser = CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_CURRENT);
RT_ASSERTE(m_pThreadUser);
}
RT_ASSERTE(m_pThreadUser != m_pThreadNetwork);
}


注1:通过CRtThreadManager这个singleton,能找到网络线程,从而,通过对网络线程PostEvent,出发PostMessage动作,从而触发WM_WIN32_SOCKET_NOTIFY消息响应应。

注2:网络线程只有一个,所有线程要发送信息,只能通过PostEvent()来发请求,由网络线程去执行。


* CRtReactor::PostEvent

// this function can be invoked in the different thread.
RtResult CRtReactorBase::PostEvent(IRtEvent* aEvent, EPriority aPri)
{
DWORD dwOldSize = 0;
RtResult rv = CRtEventQueueUsingMutex::
PostEventWithOldSize(aEvent, aPri, &dwOldSize);
if (RT_SUCCEEDED(rv) && dwOldSize == 0)
return NotifyHandler(NULL, IRtEventHandler::EVENTQUEUE_MASK);             // Why this ?
return rv;
}


Q:PostEvent的本质就是把一个event对象放进event list里,再等event queue去处理,但在win32平台中,处理如何与Windows Messaging连在一起的?



* 真正发生连接远端的地方:先注册Handler,然后连接,这样,一旦连接时sync包发出,若后续有接收,就能够触发ASYNCSELECT事件。

CRtConnectorTcpT::Connect_i()

{

...

RtResult rv = m_pReactor->RegisterHandler(this, IRtEventHandler::CONNECT_MASK);
if (RT_FAILED(rv))
return -1;


nRet = ::connect((RT_SOCKET)sockPeer.GetHandle(), 
 reinterpret_cast<const struct sockaddr *>(aAddr.GetPtr()), 
 aAddr.GetSize());

...

}


2. 理解PostEvent以及Win32下与Windows Message之间关系


* 从主线程向network thread PostEvent


# STACK TRACE

CRtEventQueueBase::PostEvent(IRtEvent * 0x0208d350, IRtEventQueue::EPriority EPRIORITY_NORMAL) line 119
CRtEventQueueUsingMutex::PostEventWithOldSize(IRtEvent * 0x0208d350, IRtEventQueue::EPriority EPRIORITY_NORMAL, unsigned long * 0x00125ef4) line 267 + 16 bytes
CRtReactorBase::PostEvent(IRtEvent * 0x0208d350, IRtEventQueue::EPriority EPRIORITY_NORMAL) line 517 + 23 bytes
CRtConnectorThreadProxy::AsycConnect(IRtAcceptorConnectorSink * 0x0208d048, const CRtInetAddr & {...}, CRtTimeValue * 0x0208cf20, CRtInetAddr * 0x00000000) line 105 + 59 bytes
CRtDetectionConnector::CConnectorItem::AsycConnect(CRtTimeValue * 0x0208cf20, CRtInetAddr * 0x00000000) line 214 + 46 bytes
CRtDetectionConnector::StartDetectionConnect(IRtAcceptorConnectorSink * 0x0208d280, CRtTimeValue * 0x0012c304, IRtDetectionConnector::DetectMode DETECT_INTERVAL_1S, CRtInetAddr * 0x00000000) line 78
CRtIMConnProvider::Connect_i(IConnProviderSink * 0x0208cb00, unsigned long 1, const TransportAddress * 0x0208cd00, Event_Type EVENT_TYPE_CONFERENCE_PING, CRtTimeValue * 0x0012c304, int 0, int 1) line 454 + 39 bytes
CRtIMConnProvider::Connect(IConnProviderSink * 0x0208cb00, unsigned long 1, const TransportAddress * 0x0208cd00, Event_Type EVENT_TYPE_CONFERENCE_PING, CRtTimeValue * 0x0012c304, int 0) line 356
CPingBase::Ping() line 116 + 51 bytes
CPingBase::StartPing() line 93
CConference::JoinConference(const CConfDetailInfo & {...}, const CInfoRosterInfo & {...}, unsigned short 1, const CRtString * 0x0208954c {0x020899c9 "tcp://192.168.1.100:443"}, int 0, unsigned long 2147483648) line 225 + 24 bytes
CConfManage::CreateConference() line 2617 + 103 bytes
CMainFrame::OnCreate(unsigned int 1, unsigned int 1, unsigned int 1, unsigned int 1) line 1879
CMainFrame::ProcessWindowMessage(HWND__ * 0x00080e54, unsigned int 1, unsigned int 0, long 1269856, long & -858993460, unsigned long 0) line 138 + 37 bytes
ATL::CWindowImplBaseT<ATL::CWindow,ATL::CWinTraits<114229248,262400> >::WindowProc(HWND__ * 0x02088920, unsigned int 1, unsigned int 0, long 1269856) line 2110 + 37 bytes
USER32! 77d18734()
USER32! 77d2bdf1()
USER32! 77d28ea0()
USER32! 77d2ce7c()
NTDLL! 7c92e473()
USER32! 77d2e442()
USER32! 77d2e4dc()
WTL::CFrameWindowImplBase<ATL::CWindow,ATL::CWinTraits<114229248,262400> >::Create(HWND__ * 0x00000000, ATL::_U_RECT {...}, const char * 0x001366e0, unsigned long 114229248, unsigned long 262400, ATL::_U_MENUorID {...}, unsigned short 50089, void * 0x00000000) line 456 + 91 bytes
WTL::CFrameWindowImpl<CMainFrame,ATL::CWindow,ATL::CWinTraits<114229248,262400> >::Create(HWND__ * 0x00000000, ATL::_U_RECT {...}, const char * 0x001366e0, unsigned long 114229248, unsigned long 262400, HMENU__ * 0x27bd0d3f, void * 0x00000000) line 1196
WTL::CFrameWindowImpl<CMainFrame,ATL::CWindow,ATL::CWinTraits<114229248,262400> >::CreateEx(HWND__ * 0x00000000, ATL::_U_RECT {...}, unsigned long 0, unsigned long 0, void * 0x00000000) line 1221 + 42 bytes
Run(char * 0x00151f28, int 1) line 195 + 35 bytes
LaunchConf(HINSTANCE__ * 0x00400000, char * 0x00151f28, int 1) line 318 + 13 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f28, int 1) line 85 + 20 bytes
WinMainCRTStartup() line 330 + 54 bytes
KERNEL32! 7c817077()


# CODE 

RtResult CRtEventQueueBase::PostEvent(IRtEvent *aEvent, EPriority aPri)
{
RT_ASSERTE_RETURN(aEvent, RT_ERROR_INVALID_ARG);


if (m_bIsStopped) {
RT_ERROR_TRACE("CRtEventQueueBase::PostEvent, has been stopped.");
aEvent->OnDestorySelf();
return RT_ERROR_NOT_INITIALIZED;
}


m_Events.push_back(aEvent);               // m_Events == 0x02087db0
m_dwSize++;


#ifndef RT_DISABLE_EVENT_REPORT
CRtTimeValue tvCur = CRtTimeValue::GetTimeOfDay();
if (tvCur - m_tvReportSize > CRtTimeValue(3, 0)) {
if (m_dwSize > 100)
RT_ERROR_TRACE("CRtEventQueueBase::PostEvent,"
" m_dwSize=" << m_dwSize << 
" m_Tid=" << m_Tid);
m_tvReportSize = tvCur;
}
#endif // !RT_DISABLE_EVENT_REPORT

return RT_OK;
}


RtResult CRtReactorBase::PostEvent(IRtEvent* aEvent, EPriority aPri)
{
DWORD dwOldSize = 0;
RtResult rv = CRtEventQueueUsingMutex::
PostEventWithOldSize(aEvent, aPri, &dwOldSize);
if (RT_SUCCEEDED(rv) && dwOldSize == 0)
return NotifyHandler(NULL, IRtEventHandler::EVENTQUEUE_MASK);
return rv;
}



* 网络thread之接收(通过Windows Message)

# STACK TRACE

CRtEventQueueBase::PopPendingEvents(std::list<IRtEvent *,std::allocator<IRtEvent *> > & {...}, unsigned long 5, unsigned long * 0x02336af8) line 177
CRtEventQueueUsingMutex::PopPendingEventsWithoutWait(std::list<IRtEvent *,std::allocator<IRtEvent *> > & {...}, unsigned long 5, unsigned long * 0x02336af8) line 134 + 20 bytes
CRtReactorBase::ProcessHandleEvent(void * 0xffffffff, long 256, int 0, int 1, int 0) line 322 + 27 bytes
CRtReactorWin32Message::Win32SocketWndProc(HWND__ * 0x00140e0a, unsigned int 1058, unsigned int 4294967295, long 256) line 115
USER32! 77d18734()
USER32! 77d18816()
USER32! 77d189cd()
USER32! 77d196c7()
CRtReactorWin32Message::RunEventLoop() line 262 + 15 bytes
CRtThreadReactor::OnThreadRun() line 67 + 19 bytes
CRtThread::ThreadProc(void * 0x02087e50) line 151 + 13 bytes
_threadstartex(void * 0x02087f00) line 227 + 13 bytes
KERNEL32! 7c80b729()


# CODE 

RtResult CRtEventQueueBase::
PopPendingEvents(EventsType &aEvents, DWORD aMaxCount, DWORD *aRemainSize)
{
    // 对m_Events列表进行操作。这里的m_Events的地址与PostEvent中指向同一memory,m_Events == 0x02087db0

}


总结:主线程(UI)向网络线程发送事件过程


a) 主线程:获得网络线程的Reactor指针pReactor

b) 主线程:pReactor->PostEvent(),这里会向Reactor(也是一种EventQueue)的m_Events中放入aEvent

c)主线程:pReactor->NotifyHandler(),这里Win32下会调用::PostMessage()通知网络线程

d) 网络线程:网络线程的消息循环RunEvent(实质就是Windows Messaging)会得到Windows的WM_WIN32_SOCKET_NOTIFY,并交由Win32SocketWndProc处理

e)网络线程:Win32SocketWndProc从Windows线程中得到CRtReactorWin32Asynselect的指针并调用PopPendingEvents处理相关events。


Q:为什么不在PostEvent中直接触发线程的处理(PopPendingEvents)?

       A:通过Windows的messaging后,处理与投递变成异步的了,在不同的线程中工作!



杂问:

Q:Win32中,网络输出的时候使用Windows Message消息吗?只有输入的时候才这样?

Q:有办法在VC环境Debug环境中看到子线程之间的父子关系吗?

Q:在



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值