Chinaunix首页 | 论坛 | 博客
  • 博客访问: 829605
  • 博文数量: 125
  • 博客积分: 4066
  • 博客等级: 上校
  • 技术积分: 1401
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-03 18:58
文章分类

全部博文(125)

文章存档

2014年(1)

2013年(1)

2012年(2)

2011年(29)

2010年(92)

我的朋友

分类: LINUX

2010-05-13 10:59:37

:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://bigwhite.blogbus.com/logs/61582046.html

在电信领域业务中,“”的应用场景较为常见。在部门的多个产品中,就有几种“生产者-消费者”应用场景的实现。本周部门内部做了一次技术交流,谈到不同产品中关于“生产者-消费者”模式实现的差异以及优劣,这里汇总了一下思路简要说明一下。

“生产者-消费者”问题又被称作“有限缓冲区”问题,即至少一个生产者与至少一个消费者针对一个公用的初始大小固定的缓冲区进行操作。

首先缓冲区是公用的或者说是共享的。Producer进程(简称P进程,这里我们主要针对进程间的P-C问题)将消息生产出来后,放入缓冲区,Consumer进程(简称C进程)从缓冲区取出消息。这个缓冲区一般被实现为,比如基于共享内存队列结构。

有了缓冲区后,下面就是P进程和C进程之间如何配合的问题了。

信 手拈来的简单方案:我们可以通过进程间的互斥锁对缓冲区进行互斥访问以解决多个P进程和P个C进程之间的配合问题。这样P、C进程,特别是C进程在实现逻 辑上相对较为简单,即不停的尝试去lock mutex,但多数时间C进程可能都在忙等待,空耗计算资源。这种配合基本上完全由操作系统调度来完成对缓冲区的互斥操作。

为了减少忙等待,对P、C的配合过程增加一些控制力,可提出进一步的方案:采用条件变量。C进程在条件变量上等待,P进程生产出数据后,可采用特定逻辑去唤醒某个C或者全部C进程(broadcast)。

以上两个方案都很简单,但都有一个较为严重的缺陷,那就是C进程多数情况下都在挂起状态,在缓冲区没有数据的情况下也无法去做别的事情。当然如果你的应用场景就是这样的,那就无可厚非了。

我们的应用场景不是这样的,所以我们还要继续演进下去。

很久以前部门的一位大牛同事就给出了一个方案:依旧是基于条件变量,不同的是在C进程中创建了一个工作线程,并由该工作线程来做条件变量的等待。同时每个C进程中工作线程和主线程通过Pipe的方式配合。P进程主线程生成一条数据后,就会发起一个唤醒操作。被唤醒的C进程的工作线程则通过Pipe告知主线程,主线程一般通过多路复用( or poll)监听Pipe并及时获得通知去获取缓冲去数据。这个方案还是蛮有灵光的,除了为每个C无端地增加了一个监听线程。这个方案在我们的产品中运行了 N多年,多数情况下很是稳定好用,但是也时常出现工作线程无法退出的问题:当C进程退出前,工作线程因无法从条件变量的阻塞状态下唤醒并退出,导致主线程 在join该工作线程时挂起而无法退出。

另外一个开发部实现了一种替代方案:采用可靠信号机制+进程内Pipe机制。P进程在生产后数据发送Unix可靠信号(> SIGRTMIN)给所有注册的C进程。C进程设置的可靠信号处理函数的逻辑较为简单,就是向Pipe写入一个字节数据,这样当信号中断处理完毕后,C进 程就可以收到Pipe的POLL_IN事件了。这种机制在线运行了两年多,没出现什么重大问题,不过Unix信号机制我们平时较少使用,有一定忌惮,也有 一些担心的:
- 软中断,一旦有不可重入的函数调用,会带来很大隐患;
- 调试困难
- 如果C进程众多,则每次都要发出大量信号,

这 两天脑子中也考虑出一种方案(尚未完善),这里也不妨说一下:通过Unix FIFO做P、C进程间通知的机制。FIFO机制简单、数据可靠,且在一定数据长度下的数据写入都是原子操作。FIFO与缓冲区一道做初始化创建,欲操作 缓冲区的P、C进程都要事先打开FIFO以写入或读出数据。P进程输出数据后,向FIFo写入数据以表示通知。某个C进程从FIFO中读取通知并开始处理 缓冲区数据,每个进程一般只从FIFO读取一个字节表示收到信号。深入思考一下,该机制虽然避免了前面提到的几个问题,同时还是有若干看起来别扭的地方:
- 需传入FIFO名字,
- 每次只有一个C进程能得到事件通知,无法做到broadcast。
- FIFO销毁前应注意检查注册到该FIFO上的进程是否都detached了。

以上几种思路仅供参考。

阅读(6901) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~