Linux平台上实现队列
转载: http://my.oschina.net/sundq/blog/203600
Linux上目前有两种事件通知方式,一种是线程条件变量,一种是利用eventfd实现事件通知,下面介绍一下利用这两种方法实现异步队列的方法。
线程条件变量
相关函数介绍
- pthread_cond_init:初始化一个线程条件变量。
- pthread_cond_wait:等待条件触发。
- pthread_cond_signal:通知一个线程,线程条件发生。
- pthread_cond_timedwait:等待条件触发,可以设置超时时间。
- pthread_cond_reltimedwait_np:和pthread_cond_timedwait使用基本相同,区别是使用的是相对时间间隔而不是绝对时间间隔。
- pthread_cond_broadcast:通知所有等待线程,线程条件发生。
- pthread_cond_destroy:销毁条件变量。
唤醒丢失问题
如果线程未持有与条件相关联的互斥锁,则调用 pthread_cond_signal() 或 pthread_cond_broadcast() 会产生唤醒丢失错误。满足以下所有条件时,即会出现唤醒丢失问题:
- 一个线程调用 pthread_cond_signal() 或 pthread_cond_broadcast()
- 另一个线程已经测试了该条件,但是尚未调用 pthread_cond_wait()
- 没有正在等待的线程
信号不起作用,因此将会丢失,仅当修改所测试的条件但未持有与之相关联的互斥锁时,才会出现此问题。只要仅在持有关联的互斥锁同时修改所测试的条件,即可调用 pthread_cond_signal() 和 pthread_cond_broadcast(),而无论这些函数是否持有关联的互斥锁。
线程条件变量使用方法
get_resources(int amount)
{
pthread_mutex_lock(&rsrc_lock);
while (resources < amount)
{
pthread_cond_wait(&rsrc_add, &rsrc_lock);
}
resources -= amount;
pthread_mutex_unlock(&rsrc_lock);
}
add_resources(int amount)
{
pthread_mutex_lock(&rsrc_lock);
resources += amount;
pthread_cond_broadcast(&rsrc_add);
pthread_mutex_unlock(&rsrc_lock);
}
eventfd
int eventfd(unsigned int initval, int flags);
eventfd 是Linux提供内核态的事件等待/通知机制,内核维护了一个8字节的整型数,该整型数由 initval 来初始化, flags 参数可以由以下值位或而来:
- EFD_CLOEXEC:设置该描述符的
O_CLOEXEC标志。 - EFD_NONBLOCK:设置描述符为非阻塞模式。
- EFD_SEMAPHORE:设置描述符为信号量工作模式,在此模式下,
read模式会使整型数减1并返回数值1。
当内核维护的8字节整型数为0时, read 操作会阻塞,如果为fd设置为非阻塞模式,则返回 EAGAIN 错误。
简单的唤醒队列
下面我们实现一个简单的环形队列:
#define default_size 1024 typedef struct queue
{
int header;
int tail;
int size;
int capcity;
void **_buf;
} queue_t; queue_t *queue_create(int size)
{
queue_t *q = malloc(sizeof (queue_t));
if (q != NULL)
{
if (size > 0)
{
q->_buf = malloc(size);
q->capcity = size;
}
else
{
q->_buf = malloc(default_size * sizeof (void *));
q->capcity = default_size;
}
q->header = q->tail = q->size = 0;
} return q;
} int queue_is_full(queue_t *q)
{
return q->size == q->capcity;
} int queue_is_empty(queue_t *q)
{
return q->size == 0;
} void queue_push_tail(queue_t *q, void *data)
{
if (!queue_is_full(q))
{
q->_buf[q->tail] = data;
q->tail = (q->tail + 1) % q->capcity;
q->size++;
}
} void *queue_pop_head(queue_t *q)
{
void *data = NULL;
if (!queue_is_empty(q))
{
data = q->_buf[(q->header)];
q->header = (q->header + 1) % q->capcity;
q->size--;
}
return data;
} int *queue_free(queue_t *q)
{
free(q->_buf);
free(q);
}
线程变量实现的异步队列
typedef struct async_queue
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int waiting_threads;
queue_t *_queue;
} async_queue_t;
async_queue_t *async_queue_create(int size)
{
async_queue_t *q = malloc(sizeof (async_queue_t));
q->_queue = queue_create(size);
q->waiting_threads = 0;
pthread_mutex_init(&(q->mutex), NULL);
pthread_cond_init(&(q->cond), NULL); return q;
} void async_queue_push_tail(async_queue_t *q, void *data)
{
if (!queue_is_full(q->_queue))
{
pthread_mutex_lock(&(q->mutex));
queue_push_tail(q->_queue, data);
if (q->waiting_threads > 0)
{
pthread_cond_signal(&(q->cond));
}
pthread_mutex_unlock(&(q->mutex));
} } void *async_queue_pop_head(async_queue_t *q, struct timeval *tv)
{
void *retval = NULL;
pthread_mutex_lock(&(q->mutex));
if (queue_is_empty(q->_queue))
{
q->waiting_threads++;
while (queue_is_empty(q->_queue))
{
pthread_cond_wait(&(q->cond), &(q->mutex));
}
q->waiting_threads--;
}
retval = queue_pop_head(q->_queue);
pthread_mutex_unlock(&(q->mutex));
return retval;
} void async_queue_free(async_queue_t *q)
{
queue_free(q->_queue);
pthread_cond_destroy(&(q->cond));
pthread_mutex_destroy(&(q->mutex));
free(q);
}
eventfd实现的异步队列
typedef struct async_queue
{
int efd; //event fd
fd_set rdfds; //for select
queue_t *_queue;
} async_queue_t;
async_queue_t *async_queue_create(int size)
{
async_queue_t *q = malloc(sizeof (async_queue_t)); q->efd = eventfd(0, EFD_SEMAPHORE|EFD_NONBLOCK);
q->_queue = queue_create(size);
FD_ZERO(&(q->rdfds));
FD_SET(q->efd, &(q->rdfds)); return q;
} void async_queue_push_tail(async_queue_t *q, void *data)
{
unsigned long long i = 1;
if (!queue_is_full(q->_queue))
{
queue_push_tail(q->_queue, data);
write(q->efd, &i, sizeof (i));
}
} void *async_queue_pop_head(async_queue_t *q, struct timeval *tv)
{
unsigned long long i = 0;
void *data = NULL;
if (select(q->efd + 1, &(q->rdfds), NULL, NULL, tv) == 0)
{
return data;
}
else
{
read(q->efd, &i, sizeof (i));
return queue_pop_head(q->_queue);
}
} void async_queue_free(async_queue_t *q)
{
queue_free(q->_queue);
close(q->efd);
free(q);
}
总结
两种实现方法线程条件变量比较复杂,但是性能略高,而eventfd实现简单,但是性能略低。
Linux平台上实现队列的更多相关文章
- 如何在linux平台上编译安装zlib软件(公司部分线上机器缺少zlib不能安装supervisor)
文章在Centos 6.5 linux平台上演示一下如何进行编译安装zlib软件,并配置相关的选项加载使用.示范从下载到安装并配置进行使用过程一系列整套讲解,希望可以给网友考虑使用,谢谢. 工具 ...
- Linux平台上轻松安装与配置Domino
Linux平台上轻松安装与配置Domino Domino Server的编译安装过程中需要用到libstdc++-2.9和glibc-2.1.1(或者其更高的版本)两个编译模块,它们是Linux开发编 ...
- 在LINUX平台上手动创建多个实例(oracle11g)
在LINUX平台上手动创建多个实例(oracle11g) http://blog.csdn.net/sunchenglu7/article/details/39676659 ORACLE linux ...
- Jexus是一款Linux平台上的高性能WEB服务器和负载均衡网关
什么是Jexus Jexus是一款Linux平台上的高性能WEB服务器和负载均衡网关,以支持ASP.NET.ASP.NET CORE.PHP为特色,同时具备反向代理.入侵检测等重要功能.可以这样说,J ...
- Linux平台上常用到的c语言开发程序
Linux操作系统上大部分应用程序都是基于C语言开发的.小编将简单介绍Linux平台上常用的C语言开发程序. 一.C程序的结构1.函数 必须有一个且只能有一个主函数main(),主函数的名为main. ...
- [4G]Linux平台上实现4G通信
转自:http://blog.sina.com.cn/s/blog_7880d3350102wb92.html 在ARM平台上实现4G模块的PPP拨号上网,参考网上的资料和自己的理解,从一无所知到开发 ...
- windows平台是上的sublime编辑远程linux平台上的文件
sublime是个跨平台的强大的代码编辑工具,不多说. 想使用sublime完毕linux平台下django网站的代码编辑工作以提高效率(原来使用linux下的vim效率较低,适合编辑一些小脚本). ...
- Domino V8 在 UNIX/Linux 平台上的安装及其常见问题
在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 Domino V8 的安装需求 Domino V8 可以支持多种平台和操作系统,表1 列出了其支持的各种 UNIX/Lin ...
- Linux平台上搭建apache+tomcat负载均衡集群
传统的Java Web项目是通过tomcat来运行和发布的.但在实际的企业应用环境中,采用单一的tomcat来维持项目的运行是不现实的.tomcat 处理能力低,效率低,承受并发小(1000左右).当 ...
随机推荐
- u-boot中环境变量的实现
转载:http://blog.chinaunix.net/uid-28236237-id-3867041.html U-boot中通过环境参数保存一些配置,这些配置可以通过修改环境参数.保存环境参数. ...
- 结构体序列为JSON
结构体序列为JSON 本例运行效果图: uses SynCommons; const /// JSON字符串 JSON1 = '{' + #13#10 + '"glossary": ...
- 适配高分辨率的图片High DPI Images for Variable Pixel Densities
用最高的效率与性能提供最好的图片质量. 本文内容来至http://www.html5rocks.com/en/mobile/high-dpi/.是在这篇文章的翻译的基础上进行了总结和说明. 眼下面临的 ...
- Cocos2d-x3.2 TextureCache类异步载入功能解说
本文TextureCache类异步载入功能的代码抽出,总共代码就200多行.感兴趣能够看看. 研究这个主要是由于项目中须要异步插入数据,但之前的方法在Android上总是崩溃所以想到TextureCa ...
- Unity3d 换装 之 模型动画分离
在手游中换装成了越来越不可缺的一个功能,毫无疑问各式各样的时装为游戏增添了不同的色彩. 对于2D手游,或许是更换对应的序列帧,也或许是如同3D手游一般,更换模型动画. 对于游戏中的人物,一般分为头.上 ...
- Combogrid的onChange和onSelect
这里只作记录一下 在easyui开发过程中遇到下边两个事儿 combogrid/combotree做级联: $("#" + deptId).combotree( { url : u ...
- spring mvc 基于注解 配置默认 handlermapping
spring mvc 是类似于 Struts 的框架.他们都有一个最主要的功能就是URL路由.URL路由能将请求与响应请求处理逻辑的类(在Struts中即是action,在spring mvc 中即是 ...
- Video Tag Test
--> Video Tag Test Your browser does not support the audio element.
- django单表操作 增 删 改 查
一.实现:增.删.改.查 1.获取所有数据显示在页面上 model.Classes.object.all(),拿到数据后,渲染给前端;前端通过for循环的方式,取出数据. 目的:通过classes(班 ...
- 创建带Mipmap的osg::Image
我们常用osgDB::readImage或者osg::Image::allocateImage()方式创建Image对象, 跟深一步的带Mipmap的Image怎样创建呢? 偶然在分析osgParti ...