【Epoll】epoll+线程池实现高并发(C++)--编辑中

 在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
{



	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  

Thread.cpp 

/******************
** 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 fd)  
{  
    connfd = fd;  
}  
 
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();      
}  
 
 
 
 
 
 
 

https://blog.csdn.net/qq_38506897/article/details/82863066

 

查看一个进程可以打开文件的限制数目:open files


[root@lrw888 workspace]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7284
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7284
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited


 

posted on 2022-10-04 01:26  bdy  阅读(180)  评论(0编辑  收藏  举报

导航