可epoll队列
什么是可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队列的更多相关文章
- (转载) Linux IO模式及 select、poll、epoll详解
注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...
- Linux epoll
一. epoll函数集 epoll主要有三个函数: 1. int epoll_create(int size); 创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大.这个参数不同于 ...
- IO多路复用之epoll总结
1.基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本.相对于select和poll来说,epoll更加灵活,没有描述符限制.epoll使用一个文件描述符管理多个描述 ...
- Linux Epoll相关知识
其实在Linux下设计并发网络程序,向来不缺少方法,比如典型的Apache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型,以及 ...
- 基本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_系列函数). 操作系统中 ...
- Linux epoll 笔记(高并发事件处理机制)
wiki: Epoll优点: Epoll工作流程: Epoll实现机制: epollevent; Epoll源码分析: Epoll接口: epoll_create; epoll_ctl; epoll_ ...
- UNIX网络编程学习指南--epoll函数
epoll是select/poll的强化版,都是多路复用的函数,epoll有了很大的改进. epoll的功能 1.支持监听大数目的socket描述符 一个进程内,select能打开的fd是有限制的,有 ...
- 基本套接字编程(5) -- epoll篇
1. epoll技术 epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃 ...
- Server Develop (六) Linux epoll总结
Linux epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低效率.因为在内核中的sele ...
随机推荐
- node的超时timeout
如果在指定的时间内服务器没有做出响应(可能是网络间连接出现问题,也可能是因为服务器故障或网络防火墙阻止了客户端与服务器的连接),则响应超时,同时触发http.ServerResponse对象的time ...
- zabbix-3.2.1监控nginx-1.11.5
声明参考地址:http://www.ttlsa.com/zabbix/zabbix-monitor-nginx-performance/ 1.zabbix需要监控nginx,则nginx需要配置ngx ...
- CentOS7.6安装Redis
官网下载地址:https://redis.io/download 第一步:软件下载安装 进行安装目录:cd /opt/software (如果目录不存在,请先创建目录) 下载二进制包:wget htt ...
- 认识Excel并创建一个excel(网址:http://poi.apache.org/)
需要导入的jar包: package com.huawei.excel; import java.io.FileOutputStream; import org.apache.poi.hssf.use ...
- textarea文本域的高度随内容的变化而变化
用css控制textarea文本域的高度随内容的变化而变化,不出现滚动条. CSS代码: 复制代码 代码如下: .t_area{ width:300px; overflow-y:visible } & ...
- RimLight(轮廓光) - Shader
[RimLight(轮廓光) - Shader] RimLight指的是物体的轮廓光.效果如下: 轮廓光的强度通过 1.0 - dot(normal, eye_vector)来计算.使用这个公式,则指 ...
- Phong & BlinnPhong Specular Shader
[Phong Specular Shader] 如果物体离摄像机很远,或者不需要高精度镜面反射,则Phong模型适用. Phong模型如下: 使用前必须指定使用自定义Phong. [BlinnPhon ...
- GameObject.Active
[GameObject.Active] 用于控制一个对象是否激活,一个对象激活当且本身active=true,并且它的父结点也都active.相当API有: 1)GameObject.SetActiv ...
- linux fg&bg
[linux fg&bg] Linux 提供了 fg 和 bg 命令,让我们调度正在运行的任务. 假设你发现前台运行的一个程序需要很长的时间,但是需要干其他的事情,你就可以用 Ctrl-Z , ...
- 高性能Web服务器Nginx的配置与部署研究(9)核心模块之HTTP模块基本常用指令
一.HTTP模块的作用是什么? Nginx的HTTP模块用于控制Nginx的HTTP进程. 二.指令 1. alias 含义:指定location使用的路径,与root类似,但不改变文件的跟路径,仅适 ...