[译]预留位置队列PRQueue:多线程程序中消息输入队列和消息输出队列保持同序...

译自: http://accu.org/var/uploads/journals/overload101.pdf

        在多线程应用程序中,要求消息输入队列和消息输出队列顺序要求保持一致,而忽略多线程并发处理的顺序,这种情况是比较难处理的。在本文中,作者设计了一种新型解决方案:PRQueue(预留位置队列),较很好的解决这个问题。

        PRQueue是使用c++的两个STL的deque还有pthread线程库实现的,并且在例子中使用了两个简单的类-Mutex和Lock来展示这个逻辑。StringMsg类表现一个样本消息,QueueTest类用来测试。

        我选择STL的deque是因为deque拥有很多必要的操作(包括operator[])来实现PRQueue。特别的,有一点很重要的是push_back和pop_front()操作对于deque的元素的指针或引用来说都是有效地。

        这里有一个简单的例子来展示PRQueue的作用。首先,我们需要记录大量的多域的消息流。转化文本字符串的数字域是一个慢的且并不关键的过程,因此我们决定将这份任务分派给能够生成日志的线程来做。处理的流程如下图所示:

        因为消息的核心处理过程是发生在多线程中,消息的就绪顺序也许跟原始的输入队列不同。例如:如果一个线程从输入队列中拿走了一个报文消息后进入休眠状态,另外一个线程取出下一个报文消息,在第一个线程之前就运行完成处理这个报文消息,并把这个报文放入输出队列中。因此,这输出日志也许会无序了(我们假设消息被处理完之后才日志)。

       使用PRQueue 则以上这种场景就能避免,它将会确保在输出队列中报文的顺序和输入队列中保持一致,而不管线程处理报文的顺序如何。PRQueue的基本逻辑比较简单,当下一个报文从输入队列中取出的时候,仍然放入锁中,下一个push_back的位置。然后释放锁,并且继续处理。在这个消息报文完全处理完之后,先前请求的位置用来把这个消息放入输出队列。

     PRQueue 使用两个队列构造:'data’ 和'filled’。

     'filled’队列的一个元素使用数据填充并且能够从PRQueue弹出。一个封装类DataQueue是'data’和'filled’队列的装载器。 这种设计允许我们在确切的实现过程中分离线程安全代码,因此用户不需要关心任何锁/解锁的逻辑。

     下面让我们更详细的讨论PRQUEUE。

     PRQueue方法主要做两件事情:它从输入队列中弹出数据,并且在输出队列中保留一个位置。PUSH方法使用之前保存的位置在输出队列中保存数据。

     为了使用多线程测试PRQUEUE,PROCESS_MSG执行。它从输入队列中取出一个StringMsg,通过调用StringMsg::process()方法来处理这个消息并且push这个报文。

//------------
static void* process_msg( void* arg)
{int thidx = ++Thidx;QueueTest* quetest =(QueueTest*)arg;Msg* msg;PRQueue< Msg*>::position pos;cout << "Input thread=" << thidx << " started" << endl;for( ;;){// Wait for next message appeared in input queue,// pop it up and get push position allocated in output queuequetest->input_que.pop( msg, quetest->output_que, pos);// Process messagemsg->process( thidx);// Push processed message into output queue using acquired position	quetest->output_que.push( msg, pos);}    return NULL;
}//


POP方法不仅等待输入队列中下一个报文的到来,也通过查看’filled’队列中元素来检查这个报文是否准备弹出了。如果数据还没有填充,pop将继续阻塞等待

POP方法的处理逻辑:

1.      锁定输入队列

2.      如果输入队列非空并且顶层元素填充了数据,则pop它(否则释放掉锁并继续睡眠)

3.      锁住输出队列

4.      保留输出队列底部位置

5.      解锁输出队列

6.      解锁输入队列

代码段如下:

    // Pop data from input queue and reserve position in the output queuevoid pop( DT& data, PRQueue& outque, position& pos){Lock lk( m_mux);while( true) {if( m_que.pop( data))break;wait_while_empty();}outque.reserve_pos( pos);}


PUSH方法拷贝数据到输出队列的保留位置并且设置'filled’指示为真。它也通过发送一个通知信号来释放掉等待一个条件变量的线程。

代码段如下:

    // Simple pushvoid push( const DT& data) {Lock lk( m_mux);m_que.push( data);notify_not_empty();} 

       现在,这个消息报文按序的到达了输出队列,如果我们想要更深的扩展我们的处理链的话,可以在后面再加上一个PRQueue。在以上的测试用例中我们不会这样做:我们使用一个单一的线程简单的从输出队列中读取处理完的报文并将它们打印出来。在最后的一步,只简单的使用了pop方法(未使用第二、第三个参数:指向输出队列和保留的位置的值)。

//------------
static void* print_msg( void* arg)
{QueueTest* quetest =(QueueTest*)arg;Msg* msg;cout << "Output thread started" << endl;for( ;;){quetest->output_que.pop( msg);msg->print();delete msg;}    return NULL;
}//


总结

       在多线程应用程序中,当处理的消息流顺序需要保证的时候,本文所说的预留位置队列将会是有用的。PRQueue将会确保输出队列中报文顺序同输入队列保持一致,因为在输出队列中下一个push_back的位置在输入队列取出报文的时候就同步的保留了。当报文消息处理完成之后,所保留的位置随后将会被数据填充。

注:完整代码于此处下载:http://accu.org/content/journals/ol101/prqueue.zip(译此文时,时间较仓促,因此译文很粗糙,待时间较宽松时再细细校验)。

 

作者:lgp88 发表于2012-3-12 13:57:53 原文链接
阅读:88 评论:0 查看评论

 

转载于:https://www.cnblogs.com/moonlove/archive/2012/03/12/2509149.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434615.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 前端工作内容_java前端、java后端、java全栈工作主要内容是什么?哪个薪资高?...

摘要最近&#xff0c;听了一场关于java全栈工程师职位的简介说明&#xff0c;里面很清楚的说明了一下前端&#xff0c;后端&#xff0c;全栈都是做什么工作的。其实&#xff0c;想做这个行业&#xff0c;就应该了解职能以及技能需求&#xff0c;这样学习才能更高效。我知道一些…

用yate2实现软VoIP语音通话(SIP协议)

用yate2实现软VoIP语音通话(SIP协议) 阳光男孩 发表于 2009-01-08 2009年1月7日&#xff0c;工业与信息化部发放了三张3G牌照&#xff0c;标志着中国进入了通信技术的新时代。3G的重要特性之一是高速数据链路&#xff0c;移动上网速度大大提高。同时&#xff0c;中国移动也大…

避免頁面重復提交3/15

在用戶做資料錄入操作時時常會反映重復記錄出現,經過了解是針對新手或者性子急的用戶在儲存時多次點擊引起 有效處理方法:新增一textbox,對儲存按鈕的onclick增設js代碼:btnsave.Attributes.Add("onclick", "var tb15document.getElementById(Textbox15);var nu…

java 日志设计_Java日志设计实践(3) - 开发篇

1.选择恰当的日志级别2.输出明确的提示文字和充分的现场信息3.输出内容一行搞定&#xff0c;不要换行4.其他1.选择恰当的日志级别选择日志级别时需要遵循一些通用规范&#xff0c;不可随意定义log4j的日志级别&#xff0c;由低到高排列&#xff1a;all trace debug info warn e…

ConfigurationManager.AppSettings[] ConfigurationManager智能显示不出来

解决办法&#xff1a;在项目中添加System.Configuration引用。转载于:https://www.cnblogs.com/2008freestyle/archive/2012/03/15/2398046.html

java5的递归算法_java递归算法 java面试题(5)

Java语言是一种具有动态性的解释型语言&#xff0c;类(class)只有被加载到JVM后才能运行。当运行指定程序时&#xff0c;JVM会将编译生成的.class文件按照需求和一定的规则加载到内存中&#xff0c;并组织成为一个完整的Java应用程序。这个加载过程是由类加载器完成&#xff0c…

OpenGL ES 2.0 for iPhone Tutorial

来源&#xff1a;http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial If youre new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting! Learn how to use OpenGL ES 2.0 from the ground up! OpenGL ES is th…

java种子填充_种子填充实例运行出问题

种子填充实例运行出问题import java.awt.*;import java.applet.*;import java.awt.image.ImageProducer;import java.awt.image.MemoryImageSource;import java.util.Stack;public class scanseed extends Applet {private static final long serialVersionUID 1L;int redColo…

Mdi悬浮子窗体不超过主窗体边界

//1.设置父窗体(主窗体)的AutoScrollMinSize大于父窗体的Size//例如主窗体(400,400), AutoScrollMinSize(500,500)//2.设置主窗体的IsMdiContainer为true private void Form2_Load(object sender, EventArgs e) {//悬浮窗体 Form3 f3 new Form3();//…

Ubuntu 12.04 root用户登录设置

Ubuntu 12.04默认是不允许root登录的&#xff0c;在登录窗口只能看到普通用户和访客登录。以普通身份登陆Ubuntu后我们需要做一些修改,普通用户登录后&#xff0c;修改系统配置文件需要切换到超级用户模式,在终端窗口里面输入: sudo -s.然后输入普通用户登陆的密码&#xff0c…

java codepointbefore_Java StringBuilder codePointBefore()方法与示例

StringBuilder类codePointBefore()方法codePointBefore()方法在java.lang包中可用。codePointBefore()方法用于表示给定索引和数组索引从0到length()-1开始的Unicode代码点。codePointBefore()方法是一种非静态方法&#xff0c;仅可通过类对象访问&#xff0c;如果尝试使用类名…

随机交换检验数据挖掘结果-assessing data mining result via swap randomization

转载自己的博客&#xff1a; http://blog.csdn.net/lgnlgn/article/details/5936945 数据挖掘中一个重要的研究议题是确定发现的模式或模型是否显著。虽然传统统计方法已经早已用以进行显著性检验&#xff0c;但是在数据挖掘领域这一方法却没有得到足够的重视。在本文中提出采…

sip中的100trying到底有啥用

SIP是一种类似HTTP的基于请求响应的协议。理想情况下&#xff0c;请求被发出后&#xff0c;应该无任何延迟的传回响应。但是这是理想情况&#xff0c;有些时候接收端收到请求后进行处理需要一定的延迟&#xff0c;这个延迟是不一定的&#xff0c;SIP中有一个超时机制&#xff0…

java幂等性原理_Java接口幂等性设计原理解析

在微服务架构下&#xff0c;我们在完成一个订单流程时经常遇到下面的场景&#xff1a;一个订单创建接口&#xff0c;第一次调用超时了&#xff0c;然后调用方重试了一次在订单创建时&#xff0c;我们需要去扣减库存&#xff0c;这时接口发生了超时&#xff0c;调用方重试了一次…

intent几种传值数组、对象、集合(Array,Object,List)

1.Array private ArrayList<String> checkListnew ArrayList<String>();Intent intentnew Intent(mytext.this,show.class);intent.putStringArrayListExtra("list", checkList);startActivity(intent);调用 Intent intentthis.getIntent();ArrayList&l…

.mod.c 是什么文件

我们可以为代码清单4.1的模板编写一个简单的Makefile&#xff1a; obj-m : hello.o 并使用如下命令编译Hello World模块&#xff1a; make -C /usr/src/linux-2.6.15.5/ M/driver_study/ modules 如果当前处于模块所在的目录&#xff0c;则以下命令与上述命令同等&#xff1a…

java web Jersey_使用CXF和Jersey框架来进行Java的WebService编程

CXFCXF是在xfire的基础上实现的。1)首先呢&#xff0c;还是包的问题&#xff0c;在http://cxf.apache.org/download.html这里可以下到最新版的CXF&#xff0c;当然&#xff0c;我用的是最新版的。接下来还是那句废话&#xff0c;建WEB项目&#xff0c;放入JAR包。而JAR包我们就…

Binding是WPF的核心,WPF的常用数据源绑定有四种

Binding是WPF的核心&#xff0c;WPF的数据源有以下几种&#xff1a; 1、ADO.NET中的DataTable 2、xml数据源 3、object数据源 4、元素控件属性 详细说明见链接&#xff1a;http://www.cnblogs.com/linlf03/archive/2011/09/06/2168440.html 转载于:https://www.cnblogs.com/jun…

对 Linux 新手非常有用的 20 个命令

你打算从Windows换到Linux上来&#xff0c;还是你刚好换到Linux上来&#xff1f;哎哟&#xff01;&#xff01;&#xff01;我说什么呢&#xff0c;是什么原因你就出现在我的世界里了。从我以往的经验来说&#xff0c;当我刚使用Linux&#xff0c;命令&#xff0c;终端啊什么的…

java float什么类型数据类型_Java中的Float和double数据类型

浮点数据类型是单精度32位IEEE 754浮点数,双数据类型是双精度64位IEEE 754浮点数.这是什么意思&#xff1f;什么时候应该使用float而不是double,反之亦然&#xff1f;解决方法:总结一下&#xff1a;> float以32位表示,带有1个符号位,8位指数和23位有效数字(或者从科学数字符…