青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

牽著老婆滿街逛

嚴以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

異步消息的傳遞-回調機制

from:http://www.ibm.com/developerworks/cn/linux/l-callback/index.html

級別: 初級

陳家朋 (japen@vip.sina.com), 系統架構師和技術顧問, 杭州邁可行通信技術有限公司

2003 年 3 月 01 日

軟件模塊之間總是存在著一定的接口,從調用方式上,可以把他們分為三類:同步調用、回調和異步調用。同步調用是一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用;回調是一種雙向調用模式,也就是說,被調用方在接口被調用時也會調用對方的接口;異步調用是一種類似消息或事件的機制,不過它的調用方向剛好相反,接口的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的接口)。回調和異步調用的關系非常緊密,通常我們使用回調來實現異步消息的注冊,通過異步調用來實現消息的通知。同步調用是三者當中最簡單的,而回調又常常是異步調用的基礎,因此,下面我們著重討論回調機制在不同軟件架構中的實現。

1 什么是回調

軟件模塊之間總是存在著一定的接口,從調用方式上,可以把他們分為三類:同步調用、回調和異步調用。同步調用是一種阻塞式調用,調用方要等待對方執行完畢才返回,它是一種單向調用;回調是一種雙向調用模式,也就是說,被調用方在接口被調用時也會調用對方的接口;異步調用是一種類似消息或事件的機制,不過它的調用方向剛好相反,接口的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的接口)。回調和異步調用的關系非常緊密,通常我們使用回調來實現異步消息的注冊,通過異步調用來實現消息的通知。同步調用是三者當中最簡單的,而回調又常常是異步調用的基礎,因此,下面我們著重討論回調機制在不同軟件架構中的實現。



對于不同類型的語言(如結構化語言和對象語言)、平臺(Win32、JDK)或構架(CORBA、DCOM、WebService),客戶和服務的交互除了同步方式以外,都需要具備一定的異步通知機制,讓服務方(或接口提供方)在某些情況下能夠主動通知客戶,而回調是實現異步的一個最簡捷的途徑。

對于一般的結構化語言,可以通過回調函數來實現回調。回調函數也是一個函數或過程,不過它是一個由調用方自己實現,供被調用方使用的特殊函數。

在面向對象的語言中,回調則是通過接口或抽象類來實現的,我們把實現這種接口的類成為回調類,回調類的對象成為回調對象。對于象C++或Object Pascal這些兼容了過程特性的對象語言,不僅提供了回調對象、回調方法等特性,也能兼容過程語言的回調函數機制。

Windows平臺的消息機制也可以看作是回調的一種應用,我們通過系統提供的接口注冊消息處理函數(即回調函數),從而實現接收、處理消息的目的。由于Windows平臺的API是用C語言來構建的,我們可以認為它也是回調函數的一個特例。

對于分布式組件代理體系CORBA,異步處理有多種方式,如回調、事件服務、通知服務等。事件服務和通知服務是CORBA用來處理異步消息的標準服務,他們主要負責消息的處理、派發、維護等工作。對一些簡單的異步處理過程,我們可以通過回調機制來實現。

下面我們集中比較具有代表性的語言(C、Object Pascal)和架構(CORBA)來分析回調的實現方式、具體作用等。





回頁首


2 過程語言中的回調(C)

2.1 函數指針

回調在C語言中是通過函數指針來實現的,通過將回調函數的地址傳給被調函數從而實現回調。因此,要實現回調,必須首先定義函數指針,請看下面的例子:

void Func(char *s);// 函數原型
            void (*pFunc) (char *);//函數指針
            

可以看出,函數的定義和函數指針的定義非常類似。

一般的化,為了簡化函數指針類型的變量定義,提高程序的可讀性,我們需要把函數指針類型自定義一下。

typedef void(*pcb)(char *);
            

回調函數可以象普通函數一樣被程序調用,但是只有它被當作參數傳遞給被調函數時才能稱作回調函數。

被調函數的例子:

void GetCallBack(pcb callback)
            {
            /*do something*/
            }
            用戶在調用上面的函數時,需要自己實現一個pcb類型的回調函數:
            void fCallback(char *s)
            {
            /* do something */
            }
            然后,就可以直接把fCallback當作一個變量傳遞給GetCallBack,
            GetCallBack(fCallback);
            

如果賦了不同的值給該參數,那么調用者將調用不同地址的函數。賦值可以發生在運行時,這樣使你能實現動態綁定。





回頁首


2.2 參數傳遞規則

到目前為止,我們只討論了函數指針及回調而沒有去注意ANSI C/C++的編譯器規范。許多編譯器有幾種調用規范。如在Visual C++中,可以在函數類型前加_cdecl,_stdcall或者_pascal來表示其調用規范(默認為_cdecl)。C++ Builder也支持_fastcall調用規范。調用規范影響編譯器產生的給定函數名,參數傳遞的順序(從右到左或從左到右),堆棧清理責任(調用者或者被調用者)以及參數傳遞機制(堆棧,CPU寄存器等)。

將調用規范看成是函數類型的一部分是很重要的;不能用不兼容的調用規范將地址賦值給函數指針。例如:

// 被調用函數是以int為參數,以int為返回值
            __stdcall int callee(int);
            // 調用函數以函數指針為參數
            void caller( __cdecl int(*ptr)(int));
            // 在p中企圖存儲被調用函數地址的非法操作
            __cdecl int(*p)(int) = callee; // 出錯
            

指針p和callee()的類型不兼容,因為它們有不同的調用規范。因此不能將被調用者的地址賦值給指針p,盡管兩者有相同的返回值和參數列

2.3 應用舉例

C語言的標準庫函數中很多地方就采用了回調函數來讓用戶定制處理過程。如常用的快速排序函數、二分搜索函數等。

快速排序函數原型:

void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
            二分搜索函數原型:
            void *bsearch(const void *key, const void *base, size_t nelem,
            size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
            

其中fcmp就是一個回調函數的變量。

下面給出一個具體的例子:

#include <stdio.h>
            #include <stdlib.h>
            int sort_function( const void *a, const void *b);
            int list[5] = { 54, 21, 11, 67, 22 };
            int main(void)
            {
            int  x;
            qsort((void *)list, 5, sizeof(list[0]), sort_function);
            for (x = 0; x < 5; x++)
            printf("%i\n", list[x]);
            return 0;
            }
            int sort_function( const void *a, const void *b)
            {
            return *(int*)a-*(int*)b;
            }
            

2.4 面向對象語言中的回調(Delphi)

Dephi與C++一樣,為了保持與過程語言Pascal的兼容性,它在引入面向對象機制的同時,保留了以前的結構化特性。因此,對回調的實現,也有兩種截然不同的模式,一種是結構化的函數回調模式,一種是面向對象的接口模式。

2.4.1 回調函數

回調函數類型定義:

type
            TCalcFunc=function (a:integer;b:integer):integer;
            

按照回調函數的格式自定義函數的實現,如

function Add(a:integer;b:integer):integer
            begin
            result:=a+b;
            end;
            function Sub(a:integer;b:integer):integer
            begin
            result:=a-b;
            end;
            

回調的使用

function Calc(calc:TcalcFunc;a:integer;b:integer):integer
            

下面,我們就可以在我們的程序里按照需要調用這兩個函數了

c:=calc(add,a,b);//c=a+b
            c:=calc(sub,a,b);//c=a-b
            

2.4.2 回調對象

什么叫回調對象呢,它具體用在哪些場合?首先,讓我們把它與回調函數對比一下,回調函數是一個定義了函數的原型,函數體則交由第三方來實現的一種動態應用模式。要實現一個回調函數,我們必須明確知道幾點:該函數需要那些參數,返回什么類型的值。同樣,一個回調對象也是一個定義了對象接口,但是沒有具體實現的抽象類(即接口)。要實現一個回調對象,我們必須知道:它需要實現哪些方法,每個方法中有哪些參數,該方法需要放回什么值。

因此,在回調對象這種應用模式中,我們會用到接口。接口可以理解成一個定義好了但是沒有實現的類,它只能通過繼承的方式被別的類實現。Delphi中的接口和COM接口類似,所有的接口都繼承與IInterface(等同于IUnknow),并且要實現三個基本的方法QueryInterface, _AddRef, 和_Release。

  • 定義一個接口
    type IShape=interface(IInterface)
                    procedure Draw;
                    end
                    

  • 實現回調類
    type TRect=class(TObject,IShape)
                    protected
                    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
                    function _AddRef: Integer; stdcall;
                    function _Release: Integer; stdcall;
                    public
                    procedure Draw;
                    end;
                    type TRound=class(TObject,IShape)
                    protected
                    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
                    function _AddRef: Integer; stdcall;
                    function _Release: Integer; stdcall;
                    public
                    procedure Draw;
                    end;
                    

  • 使用回調對象
    procedure MyDraw(shape:IShape);
                    var
                    shape:IShape;
                    begin
                    shape.Draw;
                    end;
                    

如果傳入的對象為TRect,那么畫矩形;如果為TRound,那么就為圓形。用戶也可以按照自己的意圖來實現IShape接口,畫出自己的圖形:

MyDraw(Trect.Create);
            MyDraw(Tround.Create);
            

2.4.3 回調方法

回調方法(Callback Method)可以看作是回調對象的一部分,Delphi對windows消息的封裝就采用了回調方法這個概念。在有些場合,我們不需要按照給定的要求實現整個對象,而只要實現其中的一個方法就可以了,這是我們就會用到回調方法。

回調方法的定義如下:

TNotifyEvent = procedure(Sender: TObject) of object;
            TMyEvent=procedure(Sender:Tobject;EventId:Integer) of object;
            

TNotifyEvent 是Delphi中最常用的回調方法,窗體、控件的很多事件,如單擊事件、關閉事件等都是采用了TnotifyEvent。回調方法的變量一般通過事件屬性的方式來定義,如TCustomForm的創建事件的定義:

property OnCreate: TNotifyEvent read FOnCreate write FOnCreate stored IsForm;
            

我們通過給事件屬性變量賦值就可以定制事件處理器。

用戶定義對象(包含回調方法的對象):

type TCallback=Class
            procedure ClickFunc(sender:TObject);
            end;
            procedure Tcallback.ClickFunc(sender:TObject);
            begin
            showmessage('the caller is clicked!');
            end;
            

窗體對象:

type TCustomFrm=class(TForm)
            public
            procedure RegisterClickFunc(cb:procedure(sender:Tobject) of object);
            end;
            procedure TcustomFrm..RegisterClickFunc(cb:TNotifyEvent);
            begin
            self.OnClick=cb;
            end;
            

使用方法:

var
            frm:TcustomFrm;
            begin
            frm:=TcustomFrm.Create(Application);
            frm.RegisterClickFunc(Tcallback.Create().ClickFunc);
            end;
            





回頁首


3 回調在分布式計算中的應用(CORBA)

3.1 回調接口模型

CORBA的消息傳遞機制有很多種,比如回調接口、事件服務和通知服務等。回調接口的原理很簡單,CORBA客戶和服務器都具有雙重角色,即充當服務器也是客戶客戶。

回調接口的反向調用與正向調用往往是同時進行的,如果服務端多次調用該回調接口,那么這個回調接口就變成異步接口了。因此,回調接口在CORBA中常常充當事件注冊的用途,客戶端調用該注冊函數時,客戶函數就是回調函數,在此后的調用中,由于不需要客戶端的主動參與,該函數就是實現了一種異步機制。

從CORBA規范我們知道,一個CORBA接口在服務端和客戶端有不同的表現形式,在客戶端一般使用樁(Stub)文件,服務端則用到框架(Skeleton)文件,接口的規格采用IDL來定義。而回調函數的引入,使得服務端和客戶端都需要實現一定的樁和框架。下面是回調接口的實現模型:


3.1.1 范例

下面給出了一個使用回調的接口文件,服務端需要實現Server接口的框架,客戶端需要實現CallBack的框架:

module cb
            {
            interface CallBack;
            interface Server;
            interface CallBack
            {
            void OnEvent(in long Source,in long msg);
            };
            interface Server
            {
            long RegisterCB(in CallBack cb);
            void UnRegisterCB(in long hCb);
            };
            };
            

客戶端首先通過同步方式調用服務端的接口RegistCB,用來注冊回調接口CallBack。服務端收到該請求以后,就會保留該接口引用,如果發生某種事件需要向客戶端通知的時候就通過該引用調用客戶方的OnEvent函數,以便對方及時處理。

本文源碼 下載



關于作者

 

陳家朋,系統架構師和技術顧問,目前擔任杭州邁可行通信技術有限公司MPS2000業務交換平臺的首席設計人員。擅長架構設計、提供技術解決方案等工作,熟知計算機和通信領域的各種前沿技術。可以通過 japen@vip.sina.com跟他聯系。

posted on 2008-03-05 16:23 楊粼波 閱讀(411) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国内外成人在线视频| 欧美另类综合| 国产午夜亚洲精品理论片色戒| 亚洲视频每日更新| 一区二区高清视频| 国产欧美日韩免费| 麻豆成人av| 欧美精品在线视频| 欧美一区二区视频在线观看2020| 欧美成人精品激情在线观看| 国产美女精品视频| 欧美在线资源| 久久久久国产精品一区二区| 在线免费观看日韩欧美| 亚洲人成在线观看| 国产精品久久二区| 久热国产精品| 欧美日韩一区精品| 久久人人超碰| 欧美天堂亚洲电影院在线观看| 亚洲欧美伊人| 麻豆精品一区二区av白丝在线| 一区二区免费看| 午夜宅男欧美| 日韩亚洲在线观看| 欧美影院在线播放| 亚洲免费电影在线| 欧美在线亚洲| 亚洲欧美国产另类| 久久亚洲精品一区二区| 亚洲欧美国产日韩天堂区| 麻豆91精品| 久久精品国产91精品亚洲| 欧美日韩精品免费| 美日韩精品免费| 国产精品夜色7777狼人| 91久久在线观看| 亚洲精品三级| 韩日欧美一区二区三区| 一区二区成人精品| 亚洲久久成人| 久久精品欧美日韩| 性欧美xxxx视频在线观看| 欧美激情黄色片| 麻豆乱码国产一区二区三区| 国产欧美一区二区精品忘忧草| 亚洲日本理论电影| 亚洲国产精品成人一区二区 | 亚洲一区二区三区影院| 亚洲天堂网站在线观看视频| 亚洲精品国精品久久99热| 欧美一级黄色网| 午夜影视日本亚洲欧洲精品| 欧美精品一区二区三区高清aⅴ| 蜜臀久久99精品久久久画质超高清| 国产精品国产三级国产aⅴ无密码| 亚洲激情视频网站| 亚洲国产精品久久久久秋霞蜜臀| 欧美主播一区二区三区美女 久久精品人| 正在播放日韩| 欧美日韩在线播放| 99riav1国产精品视频| 亚洲久久一区| 欧美精品免费在线| 亚洲青色在线| 99精品视频免费全部在线| 欧美激情一区二区三区全黄 | 亚洲在线播放| 国产精品剧情在线亚洲| 亚洲私人黄色宅男| 欧美一区二区三区免费观看视频| 亚洲婷婷综合久久一本伊一区| 国产一区二区av| 欧美在线观看视频一区二区三区 | 国语自产精品视频在线看8查询8| 欧美亚洲视频一区二区| 看欧美日韩国产| 亚洲高清不卡在线观看| 欧美成年人视频网站| 亚洲久久一区| 欧美一区二区三区日韩| 国产在线精品一区二区夜色| 久久久青草婷婷精品综合日韩 | 亚洲尤物在线| 巨乳诱惑日韩免费av| 亚洲人成免费| 国产精品久久久亚洲一区 | 欧美日韩一区在线观看视频| 中国成人在线视频| 久久精品视频在线观看| 亚洲国产乱码最新视频| 欧美偷拍一区二区| 欧美一区日韩一区| 亚洲人成人99网站| 欧美一级一区| 亚洲精品一区二区三区四区高清| 国产精品高潮呻吟久久| 久久精品综合网| 日韩视频在线观看免费| 久久久亚洲综合| 亚洲午夜久久久久久久久电影院| 国产一级一区二区| 欧美日韩黄色大片| 欧美诱惑福利视频| 99视频一区| 久久夜色精品国产亚洲aⅴ| 99re热这里只有精品免费视频| 国产欧美一区二区精品仙草咪 | 亚洲欧美精品一区| 亚洲国产美女精品久久久久∴| 亚洲欧美日韩在线观看a三区| 在线观看免费视频综合| 欧美视频网站| 美女尤物久久精品| 羞羞色国产精品| 一区二区三区精品久久久| 亚洲高清激情| 久久在线91| 久久精品国产免费观看| 亚洲特级毛片| 99视频精品| 亚洲精品偷拍| 亚洲精品国产精品乱码不99 | 欧美三级乱码| 欧美乱在线观看| 麻豆精品传媒视频| 久久国产精品久久久久久电车| 99精品热6080yy久久| 亚洲欧洲一区二区天堂久久| 免费观看成人网| 久久久99精品免费观看不卡| 香蕉久久a毛片| 亚洲欧美日韩一区二区三区在线| 夜夜嗨av一区二区三区免费区| 伊人精品成人久久综合软件| 国产精品国产福利国产秒拍| 欧美成人四级电影| 免费成人高清在线视频| 久久久久九九九九| 久久天堂成人| 老司机免费视频一区二区三区| 久久久噜噜噜久噜久久| 久久夜色精品一区| 免费日韩成人| 欧美国产精品人人做人人爱| 欧美成人高清视频| 亚洲高清不卡在线| 日韩视频免费大全中文字幕| 亚洲精品一线二线三线无人区| 亚洲精品视频在线观看网站| 一本色道久久88亚洲综合88| 亚洲一区二区在线看| 午夜精品视频在线观看| 欧美在线亚洲一区| 蜜桃av噜噜一区二区三区| 欧美高清日韩| 国产精品yjizz| 国产一区二区0| 最新国产乱人伦偷精品免费网站 | 亚洲综合社区| 久久精品在这里| 欧美成人一区二区| 亚洲免费观看高清在线观看| 亚洲一区影院| 久久免费视频在线| 欧美日韩在线一区二区| 国产精品久久综合| 精品成人一区二区三区| 亚洲另类在线一区| 久久国产精品黑丝| 亚洲第一伊人| 亚洲欧美日韩国产综合| 久久综合导航| 国产精品入口麻豆原神| 亚洲高清不卡在线观看| 亚洲免费视频一区二区| 久久综合色播五月| 一区二区欧美在线观看| 久久精品首页| 国产精品久久77777| 1024欧美极品| 欧美一区1区三区3区公司| 欧美高清视频在线| 亚洲欧美成人一区二区三区| 欧美www视频| 国内成人精品视频| 亚洲一区二区三区涩| 免费久久99精品国产| 亚洲一区免费| 欧美精品一区二区三区高清aⅴ| 国产在线播放一区二区三区| 亚洲一区二区高清| 亚洲风情亚aⅴ在线发布| 欧美一区二区| 国产精品免费视频观看| 99精品视频免费观看视频| 另类欧美日韩国产在线| 亚洲欧美日韩国产一区| 欧美日韩视频| 一本一道久久综合狠狠老精东影业 |