什么是可epoll队列?

就可以使用epoll来监控队列中是否有数据的队列,当然也支持select和poll。

应用场景

一个线程,需要将队列(共享内存队列或普通队列均可)中的数据取出来,然后通过网络发送出去。如果没有可epoll队列,这个问题处理起来就比较麻烦。

代码实现

实现基于pipe,但pipe可能会产生毛刺。新的内存(2.6.22)引入了eventfd(相关的还有timerfd和signalfd),基于它的实现,不会有毛刺。

/** 可以放入Epoll监控的队列

* RawQueueClass为原始队列类名,如util::CArrayQueue

* 为线程安全类

*/

template <class RawQueueClass>

class CEpollableQueue: public CEpollable

{

typedef typename RawQueueClass::_DataType DataType;

public:

/** 构造一个可Epoll的队列,注意只可监控读事件,也就是队列中是否有数据

* @queue_max: 队列最大可容纳的元素个数

* @exception: 如果出错,则抛出CSyscallException异常

*/

CEpollableQueue(uint32_t queue_max)

:_raw_queue(queue_max)

,_push_waiter_number(0)

{

if (-1 == pipe(_pipefd)) throw sys::CSyscallException(errno, __FILE__, __LINE__);

set_fd(_pipefd[0]);

}

~CEpollableQueue()

{

close();

}

/** 关闭队列 */

virtual void close()

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

if (_pipefd[0] != -1)

{

// 让CEpollable来关闭_pipefd[0],在CEpollable::close()中将会调用

// before_close,以保持语义总是相同的

CEpollable::close();

//close_fd(_pipefd[0]);

_pipefd[0] = -1;

}

if (_pipefd[1] != -1)

{

close_fd(_pipefd[1]);

_pipefd[1] = -1;

}

}

/** 判断队列是否已满 */

bool is_full() const

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

return _raw_queue.is_full();

}

/** 判断队列是否为空 */

bool is_empty() const

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

return _raw_queue.is_empty();

}

/***

* 取队首元素

* @elem: 存储取到的队首元素

* @return: 如果队列为空,则返回false,否则返回true

*/

bool front(DataType& elem) const

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

if (_raw_queue.is_empty()) return false;

elem = _raw_queue.front();

return true;

}

/***

* 弹出队首元素

* @elem: 存储弹出的队首元素

* @return: 如果队列为空,则返回false,否则取到元素并返回true

* @exception: 如果出错,则抛出CSyscallException异常

*/

bool pop_front(DataType& elem)

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

return do_pop_front(elem);

}

void pop_front()

{

DataType elem;

(void)pop_front(elem);

}

/***

* 从队首依次弹出多个元素

* @elem_array: 存储弹出的队首元素数组

* @array_size: 输入和输出参数,存储实际弹出的元素个数

* @exception: 如果出错,则抛出CSyscallException异常

*/

void pop_front(DataType* elem_array, uint32_t& array_size)

{

uint32_t i = 0;

sys::LockHelper<sys::CLock> lock_helper(_lock);

for (;;)

{

if (!do_pop_front(elem_array[i])) break;

if (++i == array_size) break;

}

array_size = i;

}

/***

* 向队尾插入一元素

* @elem: 待插入到队尾的元素

* @millisecond: 如果队列满,等待队列非满的毫秒数,如果为0则不等待,直接返回false

* @return: 如果队列已经满,则返回false,否则插入成功并返回true

* @exception: 如果出错,则抛出CSyscallException异常

*/

bool push_back(DataType elem, uint32_t millisecond=0)

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

while (_raw_queue.is_full())

{

// 立即返回

if (0 == millisecond) return false;

// 超时等待

util::CountHelper<volatile int32_t> ch(_push_waiter_number);

if (!_event.timed_wait(_lock, millisecond))

{

return false;

}

}

char c = 'x';

_raw_queue.push_back(elem);

// write还有相当于signal的作用

while (-1 == write(_pipefd[1], &c, sizeof(c)))

{

if (errno != EINTR)

throw sys::CSyscallException(errno, __FILE__, __LINE__);

}

return true;

}

/** 得到队列中当前存储的元素个数 */

uint32_t size() const

{

sys::LockHelper<sys::CLock> lock_helper(_lock);

return _raw_queue.size();

}

private:

bool do_pop_front(DataType& elem)

{

// 没有数据,也不阻塞,如果需要阻塞,应当使用事件队列CEventQueue

if (_raw_queue.is_empty()) return false;

char c;

// read还有相当于CEvent::wait的作用

while (-1 == read(_pipefd[0], &c, sizeof(c)))

{

if (errno != EINTR)

throw sys::CSyscallException(errno, __FILE__, __LINE__);

}

elem = _raw_queue.pop_front();

// 如果有等待着,则唤醒其中一个

if (_push_waiter_number > 0) _event.signal();

return true;

}

private:

int _pipefd[2]; /** 管道句柄 */

sys::CEvent _event;

mutable sys::CLock _lock;

RawQueueClass _raw_queue; /** 普通队列实例 */

volatile int32_t _push_waiter_number; /** 等待队列非满的线程个数 */

};

可epoll队列的更多相关文章

  1. (转载) Linux IO模式及 select、poll、epoll详解

    注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...

  2. Linux epoll

    一. epoll函数集 epoll主要有三个函数: 1. int epoll_create(int size); 创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大.这个参数不同于 ...

  3. IO多路复用之epoll总结

    1.基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本.相对于select和poll来说,epoll更加灵活,没有描述符限制.epoll使用一个文件描述符管理多个描述 ...

  4. Linux Epoll相关知识

    其实在Linux下设计并发网络程序,向来不缺少方法,比如典型的Apache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型,以及 ...

  5. 基本I/O模型与Epoll简介

    5种基本的I/O模型:1)阻塞I/O ;2)非阻塞I/O; 3)I/O复用(select和poll);4)信号驱动I/O(SIGIO);5)异步I/O(POSIX.1的aio_系列函数). 操作系统中 ...

  6. Linux epoll 笔记(高并发事件处理机制)

    wiki: Epoll优点: Epoll工作流程: Epoll实现机制: epollevent; Epoll源码分析: Epoll接口: epoll_create; epoll_ctl; epoll_ ...

  7. UNIX网络编程学习指南--epoll函数

    epoll是select/poll的强化版,都是多路复用的函数,epoll有了很大的改进. epoll的功能 1.支持监听大数目的socket描述符 一个进程内,select能打开的fd是有限制的,有 ...

  8. 基本套接字编程(5) -- epoll篇

    1. epoll技术 epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃 ...

  9. Server Develop (六) Linux epoll总结

    Linux  epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低效率.因为在内核中的sele ...

随机推荐

  1. linux-强制断开远程tcp连接

    最近在做日常维护,搭建了socks代理,但是socks代理服务已经关闭了,由于其他机器还在和我的服务器保持tcp长连接 e.g. tcp ESTAB Google了一下,没找到特别好的办法,例如ipt ...

  2. PHP5 ini配置文件优化

    1.1使用tmpfs作为缓存加速缓存的文件目录 [root@php-node1 ~]# mount -t tmpfs tmpfs /dev/shm/ -o size=256m [root@php-no ...

  3. redis rdb文件解析

    http://www.ttlsa.com/python/redis-rdb-tools-analysis-of-reids-dump-file-and-memory-usage/ redis-rdb- ...

  4. 腾讯安全反病毒实验室解读“Wannacry”勒索软件

    背景 针对昨日英国医院被攻击,随后肆虐中国高校的 WannaCry 勒索事件,腾讯安全反病毒实验室第一时间给出了深度权威的分析.此次勒索事件与以往相比最大的亮点在于,勒索病毒结合了蠕虫的方式进行传播, ...

  5. 1、svn架设、基本命令

    SVN是Subversion的简称,是一个开放源代码的版本控制系统.是一项十分基础,必须能够熟练使用的工具.Apache网站:https://subversion.apache.org/ 采用C/S模 ...

  6. mongodb(三)

    索引详讲索引管理空间索引 for(var i = 0 ; i<200000 ;i++){ db.books.insert({number:i,name:i+"book"}) ...

  7. 分环境部署SpringBoot日志logback-spring.xml

    springboot按照profile进行打印日志 log4j logback slf4j区别? 首先谈到日志,我们可能听过log4j logback slf4j这三个名词,那么它们之间的关系是怎么样 ...

  8. Window虚拟内存管理(转)

    内存管理是操作系统非常重要的部分,处理器每一次的升级都会给内存管理方式带来巨大的变化,向早期的8086cpu的分段式管理,到后来的80x86 系列的32位cpu推出的保护模式和段页式管理.在应用程序中 ...

  9. 【LUA table 移除操作非常慢】

    LUA的表有插入和删除两种操作.插入操作非常快,100000次操作都在0.01S左右,而删除操作在表元素大于10000时却急速变慢,测试如下: t = {} local t1= os.clock() ...

  10. Hibernate的HQL中in参数设置

    平时经常用Hibernate,由于习惯表间不建立关联,所以HQL查询时候经常要用in语句. 我最常用的情况有2种: 1.in后是个子查询,如 FROM A WHERE A.ID IN (SELECT ...