分类:
2008-11-13 12:41:11
class CSocketThread : protected wxThreadEx
class wxThreadEx
{
friend class wxThreadExImpl;
public:
typedef wxThread::ExitCode ExitCode;
wxThreadEx(wxThreadKind kind = wxTHREAD_DETACHED);
virtual ~wxThreadEx();
wxThreadError Create(unsigned int stackSize = 0);
wxThreadError Run();
wxThread::ExitCode Wait();
virtual wxThread::ExitCode Entry() = 0;
private:
wxMutex m_mutex;
wxCondition m_condition;
bool m_detached;
bool m_started;
bool m_finished;
wxThreadExImpl *m_pThread; //指向wxThreadExImpl实例
wxThread::ExitCode m_exitCode;
};class wxThreadExImpl : public wxThread
{
public:
wxThreadExImpl(wxThreadEx* pOwner)
{
m_pOwner = pOwner;
}
virtual ExitCode Entry()
{
//仅仅调用了wxThreadEx的Entry(),这会触发真正的CSocketThread::Entry()的调用
//其实代码执行到这里时已经在thread中了,因为这个函数就是override了wxThread::Entry()
//的函数。
ExitCode exitCode = m_pOwner->Entry();
m_pOwner->m_mutex.Lock();
wxASSERT(!m_pOwner->m_finished);
m_pOwner->m_exitCode = exitCode;
m_pOwner->m_finished = true;
//使用condition variable来通知我这个thread已经完成了我的工作,那些等待我给
//m_condition发送信号的thread们,就可以从wait()中返回了,不用再block了。即
//使m_condition.wait()调用返回。
//注意这里的m_condition是wxThreadEx的condition,它用来在caller和called thread
//之间同步,下面还会看到CSocketThread的m_condition,它用来使called thread因无事
//可做而block,以及允许caller thread通过signal该m_condition来将其唤醒,这也是
//wakeupThread()函数的一个功能
m_pOwner->m_condition.Signal();
m_pOwner->m_mutex.Unlock();
return 0;
}
protected:
wxThreadEx *m_pOwner; //又指向了wxThreadEx实例
};
可以看出,wxThreadEx和wxThreadExImpl互相指向,互相配合。
下面看CSocketThread是如何启动一个thread:int Connect()
{
//connect是切入点,即启动点
wxASSERT(m_pSocket);
if (m_pHost)
delete [] m_pHost;
if (m_pPort)
delete [] m_pPort;
const wxWX2MBbuf buf = m_pSocket->m_host.mb_str();
if (!buf)
{
m_pHost = 0;
m_pPort = 0;
return EINVAL;
}
m_pHost = new char[strlen(buf) + 1];
strcpy(m_pHost, buf);
// Connect method of CSocket ensures port is in range
m_pPort = new char[6];
sprintf(m_pPort, "%d", m_pSocket->m_port);
m_pPort[5] = 0;
Start(); //调用start()
return 0;
}
int Start()
{
if (m_started)
{
m_sync.Lock();
wxASSERT(m_threadwait);
m_waiting = 0;
//如果该CSocketThread对应的真正的thread已经启动,那么用wakeupThread(true)
//来确保它没有处在没有任何命令可执行的盲目等待状态或者确保它不处在等待i/o的
//由select造成的block中,即将其唤醒。继续执行
WakeupThread(true);
m_sync.Unlock();
return 0;
}
m_started = true;
#ifdef __WXMSW__
if (m_sync_event == WSA_INVALID_EVENT)
m_sync_event = WSACreateEvent();
if (m_sync_event == WSA_INVALID_EVENT)
return 1;
#else
if (m_pipe[0] == -1)
{
//创建无名管道,这个函数创建的管道m_pipe[0]是用来读的,m_pipe[1]
//是用来写的,我们将m_pipe[0]放到我们select的readfdset中,select
//的时候,如果给block了,我们如果想唤醒他,就可以通过向m_pipe[1]
//写入数据,那么会让select返回。这也就是WakeupThread()函数的一个
//功能。
if (pipe(m_pipe))
return errno;
}
#endif
int res = Create();
if (res != wxTHREAD_NO_ERROR)
return 1;
Run(); //这个run()调用的是父类wxThreadEx::Run()
return 0;
}
//这个Run就是被调用的runwxThreadError wxThreadEx::Run()
{
//他调用的是wxThread实例的run,从而真正的启动了该thread,注意
//执行到这里的时候,本函数还是位于caller thread中。而called
//thread我们可以认为在run()调用之后,启动了。与我们此时并行开始工作了
//那么那个called thread的执行路径就跑到了wxThread::Entry()里了。
//也就是上面看到的,它最终又会调用CSoketThread::Entry().
wxThreadError error = m_pThread->Run();
if (error == wxTHREAD_NO_ERROR)
m_started = true;
return error;
}
下面就是CSocketThread::Entry()的函数体:virtual ExitCode Entry()
{
m_sync.Lock();
//循环体
while (true)
{
//所谓的idleLoop其实就是该thread没有什么事可以干,没有接收到连接命令,或者
//连接已经结束了,且thread还没有结束的一个盲目状态。如果该thread应该处于
//该状态,那么thread就会在idleLoop里block。block在CSocketThread::m_condition
//上。而如果idleLoop返回了true,表明thread不会block。应该继续执行
if (!IdleLoop())
{
//虽然idleLoop返回false的时候,本thread可能没有持有m_sync锁,也可能持有
//我们都去unlock。最终Entry()返回时,我们肯定不持有。
m_finished = true;
m_sync.Unlock();
//看样子,这个return是唯一的退出外层while循环的点,即一旦进入Entry
//要退出的话,就只能从这里退出。那么idleLoop就的返回false.即m_quit要被
//设置,而这个m_quit是在caller thread被设置的,通过调用CSocket::DetackThread
//设置的,这样才会将该called thread设置m_quit,并将其唤醒。这样他的idleLoop
//会返回false.
return 0;
}
//如果idleLoop返回真,那么此时我们肯定持有m_sync锁。
//对listen状态的处理
if (m_pSocket->m_state == CSocket::listening)
{
while (IdleLoop())
{
//我们依旧持有m_sync锁
if (m_pSocket->m_fd == -1)
{
m_waiting = 0;
//如果break出去,我们还是会持有锁
break;
}
//不管doWait()返回何值,我们依旧持有锁
if (!DoWait(0))
break;
SendEvents();
}
//执行到这里时,我们持有锁
}
else
{
//对connecting状态的处理,即,等待连接
if (m_pSocket->m_state == CSocket::connecting)
{
//用DoConnect()去建立连接
//返回false,表明失败,锁还是持有的。
if (!DoConnect())
continue;
}
//此时还是有锁的
#ifdef __WXMSW__
m_waiting |= WAIT_CLOSE;
int wait_close = WAIT_CLOSE;
#endif
//已经发出了根据当前状态作了一定处理,如: 通过调用DoConnect()
//去建立连接。下面就要进入状态循环等待,并适时发出事件通知
while (IdleLoop())
{
//idleLoop返回真,我们肯定还持有锁
if (m_pSocket->m_fd == -1)
{
m_waiting = 0;
//如果此时break,那么我们依旧持有锁
break;
}
//DoWait()就是循环检查,他会根据socket的具体情况设置m_triggered
//以表明发生了什么事情,那么我们借些来就可以通过检查m_triggered
//来看究竟发生了什么事情。
//DoWait返回后,我们依旧持有锁
bool res = DoWait(0);
if (m_triggered & WAIT_CLOSE && m_pSocket)
{
m_pSocket->m_state = CSocket::closing;
#ifdef __WXMSW__
wait_close = 0;
#endif
}
//此时break,我们依旧有锁
if (!res)
break;
//根据m_triggered的设置,发出适当的event通知上部
SendEvents();
#ifdef __WXMSW__
m_waiting |= wait_close;
#endif
//返回后,我们依旧持有锁
}
}
//再循环内部,到达此点时,是有锁的。
}
m_finished = true;
return 0;
}