内核中用的很多,整理时间子系统的时候又遇到了notification mechanism,因此做次记录:

参考:1、http://msdn.microsoft.com/en-us/library/ff649664.aspx

2、http://blog.csdn.net/lovelion/article/details/7720232

3、2.6.34

  观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。

  当某件事情发生时,有多个应用需要知道该事件发生并作出相应的反映。

Solution:

  Enable listening applications to subscribe to specific messages. Create a mechanism that sends messages to all interested subscribers. The three variations of the Publish/Subscribe pattern you can use to create a mechanism that sends messages to all interested subscribers are List-Based Publish/Subscribe, Broadcast-Based Publish/Subscribe, and Content-Based Publish/Subscribe.

  实际上内核中使用的notification 机制就是基于List-Based Publish/Subscribe,下文也着重介绍List-Based Publish/Subscribe,另外两种请阅读第一个参考链接。

List-Based Publish/Subscribe

A List-Based Publish/Subscribe pattern advises you to identify a subject and to maintain a list of subscribers for that subject. When events occur, you have the subject notify each subscriber on the subscription list. When you use this pattern, you identifytwo classes: subjects and observers. Assuming you use a push model update, you add three methods to the subject: Attach(),Detach(),and Notify().You add one method to the observer—Update().
在使用基于链表的 发布——订阅 模式时,我们需要识别出一个subject,而且维护一个对该subject感兴趣的subcriber的链表。当相关事件发生时,我们就通过该subject通知subscription list上的每一个subscriber.当我们使用该模式时,需要鉴别出两个类:subject类和observer类。假设我们使用“push model update"(类似于用链表实现栈),那么我们需要对该subject添加三个方法:Attach(),Detach(),Notifiy(),对于observer则需要添加Update()方法。

To use an observer, all interested observers register with the subject by using the Attach()method. As changes occur to the subject, the subject then calls each registered observer by using the Notify()method.

所有对事件感兴趣的observer(subscriber),通过subject的Attach()方法注册到subscriber list中。当事件发生时,subject通过Notify()方法调用注册在链表上的observer。

Publish/Subscribe的优势:

、降低耦合度:Publisher不知到subcribers的具体信息
、增加安全性:通信机制确保 发布的消息 只被送到注册的 订阅者

Publish/Subcribe的缺点:

、降低性能:如果一个subject有多个直接或间接的observer,通知过程将会占用相当一部分时间
、对程序员提出了高的要求:识别出两个类。

看下内核中的notification mechanism(通知链)是如何实现的:

 通知链的运作机制包括两个角色:
、被通知者:对某一事件感兴趣的一方。定义了当事件发生时,相应的处理函数,即回调函数。但需要事先将其注册到通知链中(被通知者注册的动作就是在通知链中增加一项)。
、通知者:事件的通知者。当检测到某个事件时,或者本身产生事件时,通知所有对该事件感兴趣的一方事件发生。它定义了一个通知链,其中保存了每一个被通知者对事件的处理函数(回调函数)。所谓“通知”就是遍历通知链中的每一项,然后调用相应的事件处理函数。 被通知者调用notifier_chain_register函数注册回调函数,该函数按照优先级将回调函数加入到通知链中。
注销回调 函数则使用notifier_chain_unregister函数,即将回调函数从通知链中删除。
通知者调用notifier_call_chain函数通知事件的到达,这个函数会遍历通知链中所有的元素,然后依次调用每一个回调函数(即完成通知动作)。 通知链技术可以概括为:事件的被通知者将事件发生时应该执行的操作通过函数指针方式保存在链表(通知链)中,然后当事件发生时通知者依次执行链表中每一个元素的回调函数完成通知。

通知链节点的数据类型:

struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block *next;
int priority;
};
priority为优先级,对于notification,priority的数值越大意味着优先级越高,在同一链表中会先被调用,当具有相同优先级的节点被插入时,后插入的放在前面(先被调用,
push model)。 从节点中的函数原型可知,返回为int类型,可能的返回值及意义:
NOTIFY_DONE             0X0000    对该事件不感兴趣

NOTIFY_OK               0X0001    成功响应该事件

NOTIFY_STOP_MASK        0X8000    该回调函数返回后停止处理后续notifier block

NOTIFY_BAD              (NOFITY_STOP_MASK|0X0002)        出错,回调函数返回后停止处理后续notifier block

NOTIFY_STOP             (NOTIFY_OK|NOFITY_STOP_MASK)     成功响应事件,回调函数返回后停止处理后续notifier block           

关于节点中函数原型作用域的unsigned long类型变量的解释:
unsigned long型参数表表示发生的事件类型,因为一个chain可能支持多个事件,此参数用来对事件进行区分。(此处可以看出notification chain与List-Based Pub-Sub
有稍微的不同,因为此处支持多个事件,相当于第一个链接中所谈的topic处理方法)

原子通知链:通知链元素的回调函数在中断上下文运行,不允许阻塞

struct atomic_notifier_head {
spinlock_t lock;
struct notifier_block *head;
};

可阻塞通知链:通知链元素的回调函数在进程上下文运行,允许阻塞:

struct blocking_notifier_head {
struct rw_semaphore rwsem;
struct notifier_block *head;
};

SRCU通知链:可阻塞通知链的一种变体:

struct srcu_notifier_head {
struct mutex mutex;
struct srcu_struct srcu;
struct notifier_block *head;
};

原始通知链:对通知链没有任何限制,所有保护机制都有调用者维护:

struct raw_notifier_head {
struct notifier_block *head;
};

Publish/Subscribe Model——Notification chain——观察者模式的更多相关文章

  1. (转)RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  2. 【转】Difference between Point-To-Point and Publish/Subscribe JMS Messaging Models

    Difference between Point-To-Point and Publish/Subscribe JMS Messaging Models   Point-to-Point (PTP) ...

  3. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  4. RabbitMQ 分发到多Consumer(Publish/Subscribe)

    上篇文章中,我们把每个Message都是deliver到某个Consumer.在这篇文章中,我们将会将同一个Message deliver到多个Consumer中.这个模式也被成为 "pub ...

  5. RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe)(转载)

    RabbitMQ系列教程之三:发布/订阅(Publish/Subscribe) (本教程是使用Net客户端,也就是针对微软技术平台的) 在前一个教程中,我们创建了一个工作队列.工作队列背后的假设是每个 ...

  6. RabbitMQ消息队列(四):分发到多Consumer(Publish/Subscribe)[转]

    上篇文章中,我们把每个Message都是deliver(提供)到某个Consumer.在这篇文章中,我们将会将同一个Message deliver(提供)到多个Consumer中.这个模式也被成为 & ...

  7. RabbitMQ学习之Publish/Subscribe(3)

    上一个教程中,我们创建了一个work queue. 其中的每个task都会被精确的传送到一个worker. 这节,我们将会讲把一个message传送到多个consumers. 这种模式叫做publis ...

  8. RabbitMQ入门教程(五):扇形交换机发布/订阅(Publish/Subscribe)

    原文:RabbitMQ入门教程(五):扇形交换机发布/订阅(Publish/Subscribe) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...

  9. RabbitMQ的发布订阅模式(Publish/Subscribe)

    一.发布/订阅(Publish/Subscribe)模式 发布订阅是我们经常会用到的一种模式,生产者生产消息后,所有订阅者都可以收到.RabbitMQ的发布/订阅模型图如下: 1.该模式下生产者并不是 ...

随机推荐

  1. DeepNLP的核心关键/NLP词的表示方法类型/NLP语言模型 /词的分布式表示/word embedding/word2vec

    DeepNLP的核心关键/NLP语言模型 /word embedding/word2vec Indexing: 〇.序 一.DeepNLP的核心关键:语言表示(Representation) 二.NL ...

  2. jsp----标签编程(JSTL)

    标签编程简介 JSP的开发是在HTML代码中嵌入了大量的Java代码,但是这样一来会使得JSP页面中充满了Java程序,修改或维护起来非常的不方便, 定义一个简单的标签----空标签 要想实现一个标签 ...

  3. WebSphere ILog JRules 域的介绍和定制

    WebSphere ILog JRules 域的介绍和定制 引言 随着企业业务的不断发展,越来越多的企业正经历着以下的情形: 企业需要对于业务系统的频繁变化做出及时的关注和响应,例如,竞争对手或经济环 ...

  4. <孙阿姨炒股记:3500元炒出千万身家的股市智慧 >读书笔记

    书在这里 个人投资者要想在中国股市上生存,并且获利,首先要“胆子小” 国家方针政策要花力气去研究 不要听小道消息,比较天下没有免费的午餐 好公司不一定就能赚钱,好的买点药抓住,好的卖点更要抓住 趋势是 ...

  5. PTS无法同步

    最近在使用PTS的时候,一直重现PTS无法同步的情况,一直显示No block source available,在查了中英各种帖子之后,终于解决了这个问题,下面是解决的办法. 在windows下运行 ...

  6. CPP_运算符重载及友元

    运算符重载 两种重载方法1)成员函数 a + b => a.operator+(b); 一个参数 2)友元函数 a + b => operator+(a, b); 两个参数. friend ...

  7. sqoop 常用命令整理(二)

    26.Validate 它用来比较源数据和目标数据的数量 它有三个接口 Validator. 它有三个接口 Validator. Property: validator Description: Dr ...

  8. 解決BufferedReader读取UTF-8文件中文乱码(转)

    读取txt文件乱码 BufferedReader read = new BufferedReader(new FileReader(new File(filename))); 解决办法: InputS ...

  9. 三篇文章了解 TiDB 技术内幕——说计算

    在这我们将关系模型简单理解为 Table 和 SQL 语句,那么问题变为如何在 KV 结构上保存 Table 以及如何在 KV 结构上运行 SQL 语句. 假设我们有这样一个表的定义: CREATE ...

  10. C++ 拷贝构造函数之const关键字

    class Complex { public: //拷贝构造函数1 Complex(const Complex &c); //拷贝构造函数2 Complex(Complex &c); ...