从零开始学习EasyDarwin(RTSP之EventThread)
2016-03-06 16:29
453 查看
本文分析下EventThread的代码,机制以及用法
EventThread侦听EasyDarwin上的所有Socket事件。我
启动了在上一步创建的sEventThread类所对应的线程
sEventThread继承于OSThread
windows平台调用_beginthreadex函数创建线程,线程函数为_Entry。(有个下划线的哦)
_Entry函数如下:
通过Win32宏定义来定义不同的函数原型
windows版本函数原型:
unsigned int WINAPI OSThread::_Entry(LPVOID inThread)
Linux版本函数原型:
void* OSThread::_Entry(void *inThread)
代码中继而调用theThread->Entry();转定义到EventThread::Entry()函数中
这段代码写的很棒,其中使用到了虚函数接口设计和线程TLS技术。
想了解TLS请移步:/article/3710098.html
从OSThread类继承的子类中必须实现Entry()函数(因为基类OSThread的Entry()为纯虚函数),将自己线程要执行的代码写在Entry()函数即可。
很方便有木有?真的学习到了,大赞一个
有Socket事件发生时处理流程:
1.构造StrPtrLen类型变量idStr,在fRefTable表中查找标识为idStr的2.OSRef类型引用。
3.通过引用指针ref找到EventContext对象
4.调用EventContext的ProcessEvent方法
5.在fRefTable释放ref引用指针
这里要着重关注ProcessEvent()方法:
ProcessEvent作为虚函数有两个实现,在这里RTSP连接和RTSP连接内的消息请求会有不同的调用分支;
EventContext类中实现了ProcessEvent方法;
EventContext的派生类TCPListenerSocket中实现了ProcessEvent方法。
各位读者好好理解下面的a和b对应的内容。
a). 建立新的RTSP连接请求事件
fRefTable表插入时间: QTSServer::StartTasks()中的 fListeners[x]->RequestEvent(EV_RE);,
存入的对象为RTSPListenerSocket
调用方法: TCPListenerSocket::ProcessEvent
方法描述: 此方法调用RTSPListenerSocket的GetSessionTask方法建立一个RTSPSession,并把相应的套接口加入侦听队列,等待RTSP请求。
然后还需调用this->RequestEvent(EV_RE)把建立RTSP连接的请求加入到侦听队列。
b). 已有RTSP连接上的RTSP请求消息事件
fRefTable表插入时间: 上一步的this->RequestEvent(EV_RE)
调用方法: EventContext::ProcessEvent
方法描述: 通过Task的Signal把对应的RTSPSession类型的Task加入到TaskThread::fTaskQueue中等待TaskThread处理。
另外介绍下TCPListenerSocket::ProcessEvent方法,RTSPSession就这这里的GetSessionTask中被创建。摘取片段进行备注说明
踏踏实实的写代码,踏踏实实的做人。
EventThread侦听EasyDarwin上的所有Socket事件。我
一. EventThread 的创建
RunServer.cpp 中StartServer函数初始化调用了 Socket::Initialize(),在该函数内即创建了EventThread类对象,但是这里仅为创建,并未启动。[code]static void Initialize() { sEventThread = new EventThread(); }
二. EventThread 的启动
[code]static void StartThread() { sEventThread->Start(); }
启动了在上一步创建的sEventThread类所对应的线程
sEventThread继承于OSThread
[code]void OSThread::Start() { #ifdef __Win32__ unsigned int theId = 0; // We don't care about the identifier fThreadID = (HANDLE)_beginthreadex( NULL, // Inherit security 0, // Inherit stack size _Entry, // Entry function (void*)this, // Entry arg 0, // Begin executing immediately &theId ); Assert(fThreadID != NULL); #elif __PTHREADS__ pthread_attr_t* theAttrP; #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING //theAttrP = &sThreadAttr; theAttrP = 0; #else theAttrP = NULL; #endif int err = pthread_create((pthread_t*)&fThreadID, theAttrP, _Entry, (void*)this); Assert(err == 0); #else fThreadID = (UInt32)cthread_fork((cthread_fn_t)_Entry, (any_t)this); #endif }
windows平台调用_beginthreadex函数创建线程,线程函数为_Entry。(有个下划线的哦)
_Entry函数如下:
[code]//代码采用的方法很赞!! #ifdef __Win32__ unsigned int WINAPI OSThread::_Entry(LPVOID inThread) #else void* OSThread::_Entry(void *inThread) //static #endif { OSThread* theThread = (OSThread*)inThread; #ifdef __Win32__ BOOL theErr = ::TlsSetValue(sThreadStorageIndex, theThread); Assert(theErr == TRUE); #elif __PTHREADS__ theThread->fThreadID = (pthread_t)pthread_self(); pthread_setspecific(OSThread::gMainKey, theThread); #else theThread->fThreadID = (UInt32)cthread_self(); cthread_set_data(cthread_self(), (any_t)theThread); #endif theThread->SwitchPersonality(); // // Run the thread theThread->Entry(); return NULL; }
通过Win32宏定义来定义不同的函数原型
windows版本函数原型:
unsigned int WINAPI OSThread::_Entry(LPVOID inThread)
Linux版本函数原型:
void* OSThread::_Entry(void *inThread)
代码中继而调用theThread->Entry();转定义到EventThread::Entry()函数中
这段代码写的很棒,其中使用到了虚函数接口设计和线程TLS技术。
想了解TLS请移步:/article/3710098.html
从OSThread类继承的子类中必须实现Entry()函数(因为基类OSThread的Entry()为纯虚函数),将自己线程要执行的代码写在Entry()函数即可。
很方便有木有?真的学习到了,大赞一个
三. EventThread 的运行
EventThread::Entry()函数中开始调用select_waitevent函数监听所有的Socket端口,直到有事件发生为止[code] if (theCurrentEvent.er_data != NULL) { //The cookie in this event is an ObjectID. Resolve that objectID into //a pointer. StrPtrLen idStr((char*)&theCurrentEvent.er_data, sizeof(theCurrentEvent.er_data)); OSRef* ref = fRefTable.Resolve(&idStr); if (ref != NULL) { EventContext* theContext = (EventContext*)ref->GetObject(); theContext->ProcessEvent(theCurrentEvent.er_eventbits); fRefTable.Release(ref); } }
有Socket事件发生时处理流程:
1.构造StrPtrLen类型变量idStr,在fRefTable表中查找标识为idStr的2.OSRef类型引用。
3.通过引用指针ref找到EventContext对象
4.调用EventContext的ProcessEvent方法
5.在fRefTable释放ref引用指针
这里要着重关注ProcessEvent()方法:
ProcessEvent作为虚函数有两个实现,在这里RTSP连接和RTSP连接内的消息请求会有不同的调用分支;
EventContext类中实现了ProcessEvent方法;
EventContext的派生类TCPListenerSocket中实现了ProcessEvent方法。
各位读者好好理解下面的a和b对应的内容。
a). 建立新的RTSP连接请求事件
fRefTable表插入时间: QTSServer::StartTasks()中的 fListeners[x]->RequestEvent(EV_RE);,
存入的对象为RTSPListenerSocket
调用方法: TCPListenerSocket::ProcessEvent
方法描述: 此方法调用RTSPListenerSocket的GetSessionTask方法建立一个RTSPSession,并把相应的套接口加入侦听队列,等待RTSP请求。
然后还需调用this->RequestEvent(EV_RE)把建立RTSP连接的请求加入到侦听队列。
b). 已有RTSP连接上的RTSP请求消息事件
fRefTable表插入时间: 上一步的this->RequestEvent(EV_RE)
调用方法: EventContext::ProcessEvent
方法描述: 通过Task的Signal把对应的RTSPSession类型的Task加入到TaskThread::fTaskQueue中等待TaskThread处理。
另外介绍下TCPListenerSocket::ProcessEvent方法,RTSPSession就这这里的GetSessionTask中被创建。摘取片段进行备注说明
[code]//获取RTSPSession的fSocket参数,然后将当前接收数据的socket赋值给该参数; theTask = this->GetSessionTask(&theSocket); if (theTask == NULL) { //this should be a disconnect. do an ioctl call? close(osSocket); if (theSocket) theSocket->fState &= ~kConnected; // turn off connected state } else//创建成功,接着创建Socket对象; { /*此处省略部分代码*/ //把刚刚建立好的RTSP连接加入到侦听队列,等待RTSP请求的到来; theSocket->Set(osSocket, &addr); theSocket->InitNonBlocking(osSocket);//初始化; //将新建的RTSPSession保存到EventContext对应的fTask属性,当该socket连接后面的消息事件到来时即将该RTSPSession任务加入到task线程中; theSocket->SetTask(theTask); theSocket->RequestEvent(EV_RE);//新对象监听读事件;(EventContext开始监听该socket连接之上发送的消息) //theTask就是新建的RTSPSession; theTask->SetThreadPicker(Task::GetBlockingTaskThreadPicker()); //The RTSP Task processing threads
踏踏实实的写代码,踏踏实实的做人。
相关文章推荐
- 排序总结归纳
- iOS - Swift - 图书展示项目
- 三月活动之“桃花朵朵开 求爱上上签”
- 10. smarty 方法
- ZooKeeper原理及使用
- poj3660 Cow Contest
- Android BLE开发之Android手机与BLE终端通信
- 解决下载文件过程中内存暴涨之---OutputStream
- 软件工程概论阅读笔记1
- C#第三节课(1)
- 今天晴朗,但是由于晚上睡眠不是很好就头昏眼花
- Numpy中如何给矩阵增加一行或一列
- TYVJ 4354 多重背包二进制优化
- Latex 参考文献类型和写法
- TYVJ 4354 多重背包二进制优化
- java多线程网页下载代码
- 华为机试题--24点游戏--In Java
- MySQL数据库复制概论
- JavaMail
- 重构代码的7个阶段