您的位置:首页 > 其它

从零开始学习EasyDarwin(RTSP之EventThread)

2016-03-06 16:29 453 查看
本文分析下EventThread的代码,机制以及用法

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


踏踏实实的写代码,踏踏实实的做人。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: