epoll+线程池实现高并发

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38506897/article/details/82863066
 

     epoll模型是linux实现高并发的一种方法,基于事件驱动模型,相比于select/poll  模型具有更高的效率,本人对epoll模型做了一个简易的封装,更多的功能还在完善中,在这里仅做学习参考用。

     在epoll编程中,有三个非常重要的函数:
      1. int epoll_create(int size)     :创建epoll 句柄, 入参是表示监听的数目是多大。
      2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)   : 事件注册函数, @param1:epoll句柄,epoli_create()的返回值,  @param2: 表示注册的行为, 有ADD事件 、MOD事件、DEL事件, @param3: 注册的fd,在网络编程中,一般为sockfd,@param4:表示事件类型,
      3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)       等待事件的产生,类似于select() 调用。

 

       在线程池上,之前的博文写过一篇关于线程池的实现,拿来即用即可。造轮子的过程虽然很枯燥也很痛苦,但当你做一个项目用到你造的轮子时还是很有成就感的(菜鸟的成就感~)。

    封装的比较简单,后续会完善。

#ifndef _CEVENT_H_
#define _CEVENT_H_
 
 
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/epoll.h>
 
#define MAX_SIZE 1024
 
enum EventType
{
    EIN = EPOLLIN,          // 读事件
    EOUT = EPOLLOUT,      // 写事件
    ECLOSE = EPOLLRDHUP,  // 对端关闭连接或者写半部
    EPRI = EPOLLPRI,      // 紧急数据到达
    EERR = EPOLLERR,      // 错误事件
    EET = EPOLLET,           // 边缘触发
    EDEFULT = EIN | ECLOSE | EERR | EET
};
 
 
class CEvent
{
public:
    CEvent();
    ~CEvent();
    int Register_event(int fd,     EventType type = EDEFULT);
    int unRegister_event(int fd);
    void* EventHandle(void* arg);
    void SetNoblocking(int v_sockfd);
    
private:
    int epfd;
    bool is_running;
    pthread_t  m_tid;
    struct events[EPOLL_SIZE];
    CThreadPoolProxy *pool;
};
 
CEvent::CEvent()
{
    
    epfd = epoll_create(MAX_SIZE);
    if(epfd == -1)
    {
        printf("epoll_create failed.");
        return -1;
    }
    pthread_t tid = 0;
    pthread_create(&tid, NULL, EventHandle, (void*)this == 0);
    m_tid = tid;
    //线程池初始化
    pool = CThreadPoolProxy::instance();
    
}
 
 
CEvent::~CEvent()
{
    if(pthread_cancel(m_tid) == 0)
    {
        pthread_join(m_tid, (void **)NULL);
    }
}
 
 
 
void CEvent::SetNoblocking(int v_sockfd)
{
    int opts = fcntl(v_sockfd,F_GETFL);
    if(opts < 0)
    {
        printf("fcntl(sockfd, F_GETFL) failed.");
        opts = opts|O_NONBLOCK;
    }
    fcntl(v_sockfd, F_SETFL, opts);
    
}
 
 
 
 
 
 
int CEvent::Register_event(int fd, EventType type = EDEFULT)
{
    SetNoblocking(fd);
    struct epoll_event ev;
    ev.data.fd = fd
    ev.events = type;
    if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        printf("epoll_ctl: EPOLL_CTL_ADD failed, fd[%d].",&fd);
        return -1;
    }
    return 0;
}
 
 
int CEvent::unRegister_event(int fd)
{
    if(epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
    {
        printf("epoll_ctl: EPOLL_CTL_DEL failed, fd[%d].",&fd);
        return -1;
    }
    return 0;
}
 
 
void* CEvent::EventHandle(void* arg)
{
    
    CEvent &event = *(CEvent*)arg;
    while(is_running)
    {
        int ret = epoll_wait(event.epfd, event.events, MAX_SIZE, -1);
        if(ret < 0)
        {
            printf("epoll_wait failed, epfd[%d]",&event.epfd);
        }
        for(int i=0; i<ret; i++)
        {
            int connfd = event.events[i].data.fd;
            
            if(event.events[i].events & EPOLLIN)
            {
                CTask* ta=new CMyTask;       //  具体的方法自己实现。
                ta->SetConnFd(connfd);
                pool->AddTask(ta);
                
            }
        }
    }
    
    
    
}
 
#endif
线程池代码:

#ifndef __THREAD_H  
#define __THREAD_H  
 
/*********************
** Filename: Thread.h
** Dsricbe: 线程池头文件
** Date: 2018.7.18
** @author: Mr.xl
***/
 
 
#include <deque>
#include <string>  
#include <pthread.h>  
  
using namespace std;  
  
/** 
 * 执行任务的类,设置任务数据并执行 
 */  
class CTask {
protected:
    string m_strTaskName;   //任务的名称
    int connfd;    //接收的地址
 
public:
    CTask() = default;
    CTask(string &taskName): m_strTaskName(taskName), connfd(NULL) {}
    virtual int Run() = 0;
    void SetConnFd(int data);   //设置接收的套接字连接号。
    int GetConnFd();
    virtual ~CTask() {}
    
};
 
 
 
 
/** 
 * 线程池类的实现 
 */  
class CThreadPool  
{  
private:  
    static  deque<CTask*> m_deqTaskList;     /** 任务队列 */  
    static  bool shutdown;                    /** 线程退出标志 */           
    int     m_iThreadNum;                     /** 线程池中启动的线程数 */  
    pthread_t   *pthread_id;  
      
    static pthread_mutex_t m_pthreadMutex;    /** 线程同步锁 */  
    static pthread_cond_t m_pthreadCond;      /** 线程同步的条件变量 */  
  
protected:  
    static void* ThreadFunc(void * threadData); /** 新线程的线程回调函数 */  
    static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */  
    static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */  
      
    int Create();          /** 创建线程池中的线程 */  
  
public:  
    CThreadPool(int threadNum = 10);  
    ~CThreadPool();
    int AddTask(CTask *task);      /** 把任务添加到任务队列中 */  
    int StopAll();                 /** 使线程池中的线程退出 */  
    int getTaskSize();             /** 获取当前任务队列中的任务数 */  
};  
// 代理类,只暴露给别人用的
class CThreadPoolProxy: public CThreadPool
{
public:
    static CThreadPool* instance()
    {
        if(NULL == m_pInstance)
        {
            m_pInstance = new CThreadPoolProxy;
            return m_pInstance;
        }
        return m_pInstance;
    }
    int AddTask(CTask *task)
    {
        return m_pthreadpool->AddTask(task);
    }
    
private:
    CThreadPoolProxy()
    {
        m_pthreadpool = new CThreadPool(5)
    }
    ~CThreadPoolProxy()
    {
        delete m_pthreadpool;
    }
    
private:
    static CThreadPoolProxy* m_pInstance;
    CThreadPool* m_pthreadpool;
};
 
 
#endif  
/******************
** Fliename: Thread.cpp
** Dscribe: 线程池实现文件
** Date: 2018.7.18
** @author: Mr.xl
***/
 
 
#include "Thread.h"  
#include <iostream>  
#include <stdio.h> 
#include <stdlib.h>
#include <deque>
 
 
 
void CTask::SetConnFd(int data)  
{  
    connfd = data;  
}  
 
int CTask::GetConnFd()
{
    return connfd;
}
/**
* 初始化数据
*/
deque<CTask*> CThreadPool::m_deqTaskList;         //任务列表  
bool CThreadPool::shutdown = false;  
      
pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;   
pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;  
  
/** 
 * 线程池管理类构造函数 
 */  
CThreadPool::CThreadPool(int threadNum)  
{  
    this->m_iThreadNum = threadNum;  
    cout << "I will create " << threadNum << " threads" << endl;  
    Create();       //*创建对象时便创建线程。
}
 
CThreadPool::~CThreadPool()
{
    pthread_mutex_destroy(&m_pthreadMutex);
    pthread_cond_destroy(&m_pthreadCond);
    
}
 
/** 
 * 线程回调函数 
 */  
void* CThreadPool::ThreadFunc(void* threadData)  
{  
    pthread_t tid = pthread_self();  
    while (1)  
    {  
 
        //* 线程开启时先上锁 */
        pthread_mutex_lock(&m_pthreadMutex);  
        while (m_deqTaskList.size() == 0 && !shutdown)  
        {  
            //* 没有任务时,线程等待状态(条件变量)*/
            pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);  
        }  
          
        if (shutdown)  
        {  
            pthread_mutex_unlock(&m_pthreadMutex);  
            printf("thread %lu will exit\n", pthread_self());  
            pthread_exit(NULL);   
        }  
          
        printf("tid %lu run\n", tid);  
            
        /** 
        * 取任务队列并处理之 
        */ 
 
        //deque<CTask*>::iterator iter = m_deqTaskList.front();
        CTask* task = m_deqTaskList.front();  
        m_deqTaskList.pop_front();
 
        //* 取完任务后释放锁*/
        pthread_mutex_unlock(&m_pthreadMutex);  
          
        task->Run(); /** 执行任务 */  
         
    }  
    return (void*)0;  
}  
 
 
 
 
 
/** 
 * 往任务队列里边添加任务并发出线程同步信号 
 */  
int CThreadPool::AddTask(CTask *task)  
{  
    pthread_mutex_lock(&m_pthreadMutex);  
    this->m_deqTaskList.push_back(task);  
    pthread_mutex_unlock(&m_pthreadMutex); 
 
    // * 添加任务 条件变量发信号,非阻塞  */
    pthread_cond_signal(&m_pthreadCond);       
    return 0;  
}  
  
/** 
 * 创建线程 
 */  
int CThreadPool::Create()  
{  
    pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);  
    for(int i = 0; i < m_iThreadNum; i++)  
    {  
        pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);  
    }  
    return 0;  
}  
 
 
 
 
 
/** 
 * 停止所有线程 
 */  
int CThreadPool::StopAll()  
{  
    /** 避免重复调用 */  
    if (shutdown)  
    {  
        return -1;    
    }  
    printf("Now I will end all threads!!\n");  
    /** 唤醒所有等待线程,线程池要销毁了 */  
    shutdown = true;  
    pthread_cond_broadcast(&m_pthreadCond);  
      
    /** 阻塞等待线程退出,否则就成僵尸了 */  
    for (int i = 0; i < m_iThreadNum; i++)  
    {  
        pthread_join(pthread_id[i], NULL);    
    }  
      
    free(pthread_id);  
    pthread_id = NULL;  
      
    /** 销毁条件变量和互斥体 */  
    pthread_mutex_destroy(&m_pthreadMutex);  
    pthread_cond_destroy(&m_pthreadCond);  
      
    return 0;  
}  
 
/** 
 * 获取当前队列中任务数 
 */  
int CThreadPool::getTaskSize()  
{  
    return m_deqTaskList.size();      
}  

————————————————
版权声明:本文为CSDN博主「可乐小浣熊」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38506897/article/details/82863066

转载于:https://my.oschina.net/u/4000302/blog/3100097

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值