libev的使用

来源:互联网 发布:ubuntu 17.04 163源 编辑:程序博客网 时间:2024/06/05 20:53

什么是Reactor模式
Reactor模式首先是事件驱动的,有一个或多个并发输入源,有一个Service Handler,有多个Request Handlers;这个Service Handler会同步的将输入的请求(Event)多路复用的分发给相应的Request Handler。

Reactor模式的优点
大大减少线程数;
事件驱动,功能复用;
解耦, 模块化;

线程数对于程序的影响:

throughput 吞吐量
latency 延时

三个loop全局量的初始化

        if ( g_RtmpHubMgr::Instance().Init( &stConfigFileIni ) == -1 )        {            break;        }        //接收RTMP流的监听;zhb        if ( g_AccessServer.Init( &stConfigFileIni ) == -1 )        {            break;        }        if ( g_PushManger::Instance().Init( &stConfigFileIni ) == -1 )        {            break;        }        g_stRtmpHubLoop.RunThread();        g_stIoLoop.RunThread();        g_stPushLoop.RunThread();

第一步:初始化,启动线程池
例如:

    //启动线程池,建立ev_run函数的所有事件的主体循环  zhb     if ( g_stIoLoop.Init( iIOThreadNum ) == -1 )    {        GAL_ERROR_PRINT << "Rtmp Server create I/O Threads failed num = " << iIOThreadNum;        GAL_ERROR << "Rtmp Server create I/O Threads failed num = " << iIOThreadNum;        return -1;    }

main函数启动线程

        g_stRtmpHubLoop.RunThread();

也就建立的libev的主体大循环

//线程池的事件主体大循环 zhbuint32_t CGEV_Loop::Event_Run( int flags ){    m_iDone = GEVBREAK_CANCEL;    do     {        //更新变动的句柄        Fd_Reify();        gev_tstamp waittime = 0.;        gev_tstamp sleeptime = 0.;        m_iPipe_Write_Wanted = 1;//标记管道可以写        //计算等待时间        Calculate_BlockingTime( flags, waittime, sleeptime );        //i/o事件获取g        m_pstEvent->Poll( this, waittime );        /*        标记管道不写,因为接下来调用i/o等待函数(select/epoll),        所以在等待期间如果发生异步调用,不要再调用管道写了,        而是等待结束后直接调用异步事件处理        */        m_iPipe_Write_Wanted = 0;        //GAL_DEBUG_PRINT << ">>>>>>>>>>>>>>> thread = " << (uint32_t)pthread_self();//      if ( m_iAsyncPending )//      {//          GAL_DEBUG_PRINT << " m_iAsyncPending = " << m_iAsyncPending;//      }        if ( m_iPipe_Write_Skipped )        {            //直接调用异步事件处理            //GAL_DEBUG_PRINT << "s w s w s w s w s w s w s w s w s w s w s w s w s w s w s w s w ";            Event_Feed( &m_stPipe_W, GEVIOMASK_CUSTOM );        }        m_iPipe_Write_Wanted = 1;//标记管道可以写        //更新时间        Time_Update( waittime + sleeptime );        //执行定时器时间        Timers_Reify();        //执行i/o事件        Event_Invoke_Pending();        //GAL_DEBUG_PRINT << "<<<<<<<<<<<<<< thread = " << (uint32_t)pthread_self();    } while ( m_iActivecnt && !m_iDone & !( flags & ( GEVRUN_ONCE | GEVRUN_NOWAIT ) ) );    if ( m_iDone == GEVBREAK_ONE )    {        m_iDone = GEVBREAK_CANCEL;    }    return m_iActivecnt;}

**第二步: 关于evloop的初始化:
获取一个ev_loop实例,有了这个ev_loop实例,那么可以设置好这个libev实例的各种Watcher,也就是可以对各类事件(Watcher)设置回调函数。**

    //启动libev实例的主体循环,启动线程池; zhb    if ( g_stRtmpHubLoop.Init( iThread ) == -1 )    {        GAL_ERROR << "framehub thread pool failed " << iThread << " failed ...";        GAL_ERROR_PRINT << "framehub thread pool failed " << iThread << " failed ...";        return -1;    }    int iE = 0;    //获取一个ev_loop实例,也就是事件循环的主体。 zhb    m_pstLoop = g_stRtmpHubLoop.GetNextLoop( iE );    GAL_DEBUG_PRINT << "loop = " << iE;    if ( m_stCMDQueue.Init() == -1 )    {        return -1;    }    //创建libev的消息watcher,并设置好回调函数 CVCPSFramehubMgr::Trigger。 zhb    m_pstThreadWatcher = m_pstLoop->Event_Async_Init( &Method_Thunk< CVCPSFramehubMgr, &CVCPSFramehubMgr::Trigger > );    m_pstThreadWatcher->data = this;    if ( m_pstLoop->Event_Async_Start( m_pstThreadWatcher ) == -1 )    {        GAL_ERROR_PRINT << "async start failed ...";        return -1;    }    //创建定时器 timer 的watcher,并设置好回调函数 。zhb    m_pstCheckTimer = m_pstLoop->Event_Timer_Init( &Method_Thunk<CVCPSFramehubMgr, &CVCPSFramehubMgr::CheckNosendFrameHub >, (gev_tstamp)60, (gev_tstamp)60 );    m_pstCheckTimer->data = this;    if ( m_pstLoop->Event_Timer_Start( m_pstCheckTimer ) == -1 )    {        GAL_ERROR_PRINT << "async start failed ...";        return -1;    }

删除之前建立的两个watcher

    m_pstLoop->Event_Async_Del( m_pstThreadWatcher );    m_pstLoop->Event_Timer_Del( m_pstCheckTimer );

关于evloop的理解
关于libev实例的evloop,evloop贯穿整个libev的所有信息,可以看到这个libev所有安排了的watcher及其回调等。

    CGEV_Loop* m_pstEventLoop;  //m_pstEventLoop 处理线程;zhb 

libev实例的初始化函数默认调用了,所以Notify 函数是默认的消息通信回调函数。

                m_ppstThreadWatcher[ i ] = m_pstEventLoop[i].Event_Async_Init( &Method_Thunk<CThreadPool,&CThreadPool::Notify > );                m_ppstThreadWatcher[ i ]->data = this;                m_pstEventLoop[i].Event_Async_Start( m_ppstThreadWatcher[i] );

所以Trigger是libev实例的默认的消息处理函数。

void CThreadPool::Notify( GEV_IO_Watcher* w, int revents ){    if ( m_iNelts == 0 )    {        Trigger( m_pstQueue, 0 );    }    else if ( m_iNelts == 1 )    {        Trigger( &m_pstQueue[0], 0 );    }    else    {        int iE = 0;#if 0        unsigned MyThreadID = ::GetCurrentThreadId();        for ( ; iE < m_iNelts; iE++ )        {            if ( m_pThreadID[ iE ] == MyThreadID )            {                break;            }        }#else        pthread_t MyThreadID = pthread_self();        for ( ; iE < m_iNelts; iE++ )        {            if ( m_phThread[ iE ] == MyThreadID )            {                break;            }        }#endif        if ( iE == m_iNelts )        {            fprintf( stderr,"get cur thread self ID failed ...");            assert( 0 );        }        Trigger( &m_pstQueue[iE], iE );    }}

消息发送

void CThreadPool::AddAysncMsg( const PGEV_InMsgHeader& pstMsg,int iElt ){    if ( iElt < 0 )    {        return;    }    if ( m_iNelts == 0 )    {        m_pstQueue->push( pstMsg );        m_pstEventLoop->Event_Async_Send( m_ppstThreadWatcher[0] );    }    else    {        if ( iElt < m_iNelts )        {            m_pstQueue[ iElt ].push( pstMsg );            m_pstEventLoop[ iElt ].Event_Async_Send( m_ppstThreadWatcher[iElt] );        }    }}

关于 Attach 的使用

pstClient->Attach( iElt, &(m_pstEventLoop[iElt]), ullSn );
//对一个推流客户端进行初始化:包括对m_tFd 回调进行初始化 ,对时间控制 回调初始化;uint32_t CRtmpPS_Client::Attach( int iElt,CGEV_Loop* pstEventLoop,uint64_t ullSn ){    m_ullSn = ullSn;    m_iElt = iElt;    CGEV_Auxiliary::GEV_socket_set_option( m_tFd,GEV_SOCKOPT_NONBLOCK,1 );    //GAL_DEBUG_PRINT << "new client Sn = " << ullSn << " Elt = " << m_iElt;    m_pstEventLoop = pstEventLoop;    GAL_DEBUG_PRINT << "CRtmpPS_Client!  Event_IO_Init...111 ";    m_pstIO_Read = m_pstEventLoop->Event_IO_Init( m_tFd, &Method_Thunk<CRtmpPS_Client, &CRtmpPS_Client::Notify >, GEVIOMASK_READ | GEVIOMASK_ET );    m_pstIO_Read->data = this;    m_iNewEv = GEVIOMASK_READ;    m_pstEventLoop->Event_IO_Start( m_pstIO_Read );    m_iCurEv = m_iNewEv;    m_tStartTime = time(NULL);    m_pstCheckTimer = m_pstEventLoop->Event_Timer_Init( &Method_Thunk< CRtmpPS_Client,&CRtmpPS_Client::CheckTime >,(gev_tstamp)15,(gev_tstamp)15 );    m_pstCheckTimer->data = this;    m_iNewEv |= GEVIOMASK_TIMER;    m_pstEventLoop->Event_Timer_Start( m_pstCheckTimer );    m_iCurEv = m_iNewEv;    return 0;}

第三步:启动处理线程,各个libev实例正式开始运行

        g_stRtmpHubLoop.RunThread();        g_stIoLoop.RunThread();        g_stPushLoop.RunThread();

总结: libev的使用,关键就在于evloop的初始化(设置回调),搜索evloop能够看到这个libev的所有事件,所有事件的处理回调。

0 0
原创粉丝点击