• <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>
            posts - 200, comments - 8, trackbacks - 0, articles - 0

            譯自http://www.wangafu.net/~nickm/libevent-book/Ref4_event.html

            轉(zhuǎn)自
            :http://blog.sina.com.cn/s/blog_56dee71a0100qi0y.html

            libevent的基本操作單元是事件。每個(gè)事件代表一組條件的集合,這些條件包括:

            文件描述符已經(jīng)就緒,可以讀取或者寫(xiě)入

            文件描述符變?yōu)榫途w狀態(tài),可以讀取或者寫(xiě)入(僅對(duì)于邊沿觸發(fā)IO)

            超時(shí)事件

            發(fā)生某信號(hào)

            用戶觸發(fā)事件

            所有事件具有相似的生命周期。調(diào)用libevent函數(shù)設(shè)置事件并且關(guān)聯(lián)到event_base之后,事件進(jìn)入“已初始化(initialized)”狀態(tài)。此時(shí)可以將事件添加到event_base中,這使之進(jìn)入“未決(pending)”狀態(tài)。在未決狀態(tài)下,如果觸發(fā)事件的條件發(fā)生(比如說(shuō),文件描述符的狀態(tài)改變,或者超時(shí)時(shí)間到達(dá)),則事件進(jìn)入“激活(active)”狀態(tài),(用戶提供的)事件回調(diào)函數(shù)將被執(zhí)行。如果配置為“持久的(persistent)”,事件將保持為未決狀態(tài)。否則,執(zhí)行完回調(diào)后,事件不再是未決的。刪除操作可以讓未決事件成為非未決(已初始化)的;添加操作可以讓非未決事件再次成為未決的。

            構(gòu)造事件對(duì)象

            1.1 創(chuàng)建事件

            使用event_new()接口創(chuàng)建事件。

            接口
            #define EV_TIMEOUT      0x01
            #define EV_READ         0x02
            #define EV_WRITE        0x04
            #define EV_SIGNAL       0x08
            #define EV_PERSIST      0x10
            #define EV_ET           0x20

            typedef 
            void (*event_callback_fn)(evutil_socket_t, shortvoid *);

            struct event *event_new(struct event_base *base, evutil_socket_t fd,
                
            short what, event_callback_fn cb,
                
            void *arg);

            void event_free(struct event *event);

            event_new()試圖分配和構(gòu)造一個(gè)用于base的新的事件。what參數(shù)是上述標(biāo)志的集合。如果fd非負(fù),則它是將被觀察其讀寫(xiě)事件的文件。事件被激活時(shí),libevent將調(diào)用cb函數(shù),傳遞這些參數(shù):文件描述符fd,表示所有被觸發(fā)事件的位字段,以及構(gòu)造事件時(shí)的arg參數(shù)。

            發(fā)生內(nèi)部錯(cuò)誤,或者傳入無(wú)效參數(shù)時(shí),event_new()將返回NULL。

            所有新創(chuàng)建的事件都處于已初始化和非未決狀態(tài),調(diào)用event_add()可以使其成為未決的。

            要釋放事件,調(diào)用event_free()。對(duì)未決或者激活狀態(tài)的事件調(diào)用event_free()是安全的:在釋放事件之前,函數(shù)將會(huì)使事件成為非激活和非未決的。

            示例

            #include <event2/event.h>

            void cb_func(evutil_socket_t fd, short what, void *arg)
            {
                    
            const char *data = arg;
                    printf(
            "Got an event on socket %d:%s%s%s%s [%s]",
                        (
            int) fd,
                        (what
            &EV_TIMEOUT) ? " timeout" : "",
                        (what
            &EV_READ)    ? " read" : "",
                        (what
            &EV_WRITE)   ? " write" : "",
                        (what
            &EV_SIGNAL)  ? " signal" : "",
                        data);
            }

            void main_loop(evutil_socket_t fd1, evutil_socket_t fd2)
            {
                    
            struct event *ev1, *ev2;
                    
            struct timeval five_seconds = {5,0};
                    
            struct event_base *base = event_base_new();

                    
            /* The caller has already set up fd1, fd2 somehow, and make them
                       nonblocking. 
            */

                    ev1 
            = event_new(base, fd1, EV_TIMEOUT|EV_READ|EV_PERSIST, cb_func,
                       (
            char*)"Reading event");
                    ev2 
            = event_new(base, fd2, EV_WRITE|EV_PERSIST, cb_func,
                       (
            char*)"Writing event");

                    event_add(ev1, 
            &five_seconds);
                    event_add(ev2, NULL);
                    event_base_dispatch(
            base);
            }

            上述函數(shù)定義在<event2/event.h>中,首次出現(xiàn)在libevent 2.0.1-alpha版本中。event_callback_fn類型首次在2.0.4-alpha版本中作為typedef出現(xiàn)。

            1.2 事件標(biāo)志

            EV_TIMEOUT

            這個(gè)標(biāo)志表示某超時(shí)時(shí)間流逝后事件成為激活的。構(gòu)造事件的時(shí)候,EV_TIMEOUT標(biāo)志是被忽略的:可以在添加事件的時(shí)候設(shè)置超時(shí),也可以不設(shè)置。超時(shí)發(fā)生時(shí),回調(diào)函數(shù)的what參數(shù)將帶有這個(gè)標(biāo)志。

            EV_READ

            表示指定的文件描述符已經(jīng)就緒,可以讀取的時(shí)候,事件將成為激活的。

            EV_WRITE

            表示指定的文件描述符已經(jīng)就緒,可以寫(xiě)入的時(shí)候,事件將成為激活的。

            EV_SIGNAL

            用于實(shí)現(xiàn)信號(hào)檢測(cè),請(qǐng)看下面的“構(gòu)造信號(hào)事件”節(jié)。

            EV_PERSIST

            表示事件是“持久的”,請(qǐng)看下面的“關(guān)于事件持久性”節(jié)。

            EV_ET

            表示如果底層的event_base后端支持邊沿觸發(fā)事件,則事件應(yīng)該是邊沿觸發(fā)的。這個(gè)標(biāo)志影響EV_READ和EV_WRITE的語(yǔ)義。

             

            從2.0.1-alpha版本開(kāi)始,可以有任意多個(gè)事件因?yàn)橥瑯拥臈l件而未決。比如說(shuō),可以有兩個(gè)事件因?yàn)槟硞€(gè)給定的fd已經(jīng)就緒,可以讀取而成為激活的。這種情況下,多個(gè)事件回調(diào)被執(zhí)行的次序是不確定的。

            這些標(biāo)志定義在<event2/event.h>中。除了EV_ET在2.0.1-alpha版本中引入外,所有標(biāo)志從1.0版本開(kāi)始就存在了。

            1.3 關(guān)于事件持久性

            默認(rèn)情況下,每當(dāng)未決事件成為激活的(因?yàn)閒d已經(jīng)準(zhǔn)備好讀取或者寫(xiě)入,或者因?yàn)槌瑫r(shí)),事件將在其回調(diào)被執(zhí)行前成為非未決的。如果想讓事件再次成為未決的,可以在回調(diào)函數(shù)中再次對(duì)其調(diào)用event_add()。

            然而,如果設(shè)置了EV_PERSIST標(biāo)志,事件就是持久的。這意味著即使其回調(diào)被激活,事件還是會(huì)保持為未決狀態(tài)。如果想在回調(diào)中讓事件成為非未決的,可以對(duì)其調(diào)用event_del()。

            每次執(zhí)行事件回調(diào)的時(shí)候,持久事件的超時(shí)值會(huì)被復(fù)位。因此,如果具有EV_READ|EV_PERSIST標(biāo)志,以及5秒的超時(shí)值,則事件將在以下情況下成為激活的:

            套接字已經(jīng)準(zhǔn)備好被讀取的時(shí)候

            從最后一次成為激活的開(kāi)始,已經(jīng)逝去5秒

            1.4 只有超時(shí)的事件

            為使用方便,libevent提供了一些以evtimer_開(kāi)頭的宏,用于替代event_*調(diào)用來(lái)操作純超時(shí)事件。使用這些宏能改進(jìn)代碼的清晰性。

            接口

            #define evtimer_new(base, callback, arg) \
                event_new((
            base), -10, (callback), (arg))
            #define evtimer_add(ev, tv) \
                event_add((ev),(tv))
            #define evtimer_del(ev) \
                event_del(ev)
            #define evtimer_pending(ev, what, tv_out) \
                event_pending((ev), (what), (tv_out))

            除了evtimer_new()首次出現(xiàn)在2.0.1-alpha版本中之外,這些宏從0.6版本就存在了。

            1.5 構(gòu)造信號(hào)事件

            libevent也可以監(jiān)測(cè)POSIX風(fēng)格的信號(hào)。要構(gòu)造信號(hào)處理器,使用:

            接口

            #define evsignal_new(base, signum, callback, arg) \
                event_new(
            base, signum, EV_SIGNAL|EV_PERSIST, cb, arg)

            除了提供一個(gè)信號(hào)編號(hào)代替文件描述符之外,各個(gè)參數(shù)與event_new()相同。

            示例

            struct event *hup_event;
            struct event_base *base = event_base_new();

            /* call sighup_function on a HUP signal */
            hup_event 
            = evsignal_new(base, SIGHUP, sighup_function, NULL);

            注意:信號(hào)回調(diào)是信號(hào)發(fā)生后在事件循環(huán)中被執(zhí)行的,所以可以安全地調(diào)用通常不能在POSIX風(fēng)格信號(hào)處理器中使用的函數(shù)。

            警告:不要在信號(hào)事件上設(shè)置超時(shí),這可能是不被支持的。[待修正:真是這樣的嗎?]

            libevent也提供了一組方便使用的宏用于處理信號(hào)事件:

            接口

            #define evsignal_add(ev, tv) \
                event_add((ev),(tv))
            #define evsignal_del(ev) \
                event_del(ev)
            #define evsignal_pending(ev, what, tv_out) \
                event_pending((ev), (what), (tv_out))

            evsignal_*宏從2.0.1-alpha版本開(kāi)始存在。先前版本中這些宏叫做signal_add()、signal_del()等等。

            關(guān)于信號(hào)的警告

            在當(dāng)前版本的libevent和大多數(shù)后端中,每個(gè)進(jìn)程任何時(shí)刻只能有一個(gè)event_base可以監(jiān)聽(tīng)信號(hào)。如果同時(shí)向兩個(gè)event_base添加信號(hào)事件,即使是不同的信號(hào),也只有一個(gè)event_base可以取得信號(hào)。

            kqueue后端沒(méi)有這個(gè)限制。

            1.6 設(shè)置不使用堆分配的事件

            出于性能考慮或者其他原因,有時(shí)需要將事件作為一個(gè)大結(jié)構(gòu)體的一部分。對(duì)于每個(gè)事件的使用,這可以節(jié)省:

            內(nèi)存分配器在堆上分配小對(duì)象的開(kāi)銷(xiāo)

            對(duì)event結(jié)構(gòu)體指針取值的時(shí)間開(kāi)銷(xiāo)

            如果事件不在緩存中,因?yàn)榭赡艿念~外緩存丟失而導(dǎo)致的時(shí)間開(kāi)銷(xiāo)

            對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),這些開(kāi)銷(xiāo)是非常小的。所以,除非確定在堆上分配事件導(dǎo)致了嚴(yán)重的性能問(wèn)題,應(yīng)該堅(jiān)持使用event_new()。如果將來(lái)版本中的event結(jié)構(gòu)體更大,不使用event_new()可能會(huì)導(dǎo)致難以診斷的錯(cuò)誤。

            不在堆上分配event具有破壞與其他版本libevent二進(jìn)制兼容性的風(fēng)險(xiǎn):其他版本中的event結(jié)構(gòu)體大小可能不同。

            接口

            int event_assign(struct event *eventstruct event_base *base,
                evutil_socket_t fd, 
            short what,
                
            void (*callback)(evutil_socket_t, shortvoid *), void *arg);

            除了event參數(shù)必須指向一個(gè)未初始化的事件之外,event_assign()的參數(shù)與event_new()的參數(shù)相同。成功時(shí)函數(shù)返回0,如果發(fā)生內(nèi)部錯(cuò)誤或者使用錯(cuò)誤的參數(shù),函數(shù)返回-1。

            示例

            #include <event2/event.h>
            /* Watch out!  Including event_struct.h means that your code will not
             * be binary-compatible with future versions of Libevent. 
            */
            #include 
            <event2/event_struct.h>
            #include 
            <stdlib.h>

            struct event_pair {
                     evutil_socket_t fd;
                     
            struct event read_event;
                     
            struct event write_event;
            };
            void readcb(evutil_socket_t, shortvoid *);
            void writecb(evutil_socket_t, shortvoid *);
            struct event_pair *event_pair_new(struct event_base *base, evutil_socket_t fd)
            {
                    
            struct event_pair *= malloc(sizeof(struct event_pair));
                    
            if (!p) return NULL;
                    p
            ->fd = fd;
                    event_assign(
            &p->read_event, base, fd, EV_READ|EV_PERSIST, readcb, p);
                    event_assign(
            &p->write_event, base, fd, EV_WRITE|EV_PERSIST, writecb, p);
                    
            return p;
            }

            也可以用event_assign()初始化棧上分配的,或者靜態(tài)分配的事件。

            警告

            不要對(duì)已經(jīng)在event_base中未決的事件調(diào)用event_assign(),這可能會(huì)導(dǎo)致難以診斷的錯(cuò)誤。如果已經(jīng)初始化和成為未決的,調(diào)用event_assign()之前需要調(diào)用event_del()。

            libevent提供了方便的宏將event_assign()用于僅超時(shí)事件或者信號(hào)事件。

            接口

            #define evtimer_assign(event, base, callback, arg) \
                event_assign(
            eventbase-10, callback, arg)
            #define evsignal_assign(event, base, signum, callback, arg) \
                event_assign(
            eventbase, signum, EV_SIGNAL|EV_PERSIST, callback, arg)

            如果需要使用event_assign(),又要保持與將來(lái)版本libevent的二進(jìn)制兼容性,可以請(qǐng)求libevent告知struct event在運(yùn)行時(shí)應(yīng)該有多大:

            接口

            size_t event_get_struct_event_size(void);

            這個(gè)函數(shù)返回需要為event結(jié)構(gòu)體保留的字節(jié)數(shù)。再次強(qiáng)調(diào),只有在確信堆分配是一個(gè)嚴(yán)重的性能問(wèn)題時(shí)才應(yīng)該使用這個(gè)函數(shù),因?yàn)檫@個(gè)函數(shù)讓代碼難以閱讀和編寫(xiě)。

            注意,將來(lái)版本的event_get_struct_event_size()的返回值可能比sizeof(struct event)小,這表示event結(jié)構(gòu)體末尾的額外字節(jié)僅僅是保留用于將來(lái)版本libevent的填充字節(jié)。

            下面這個(gè)例子跟上面的那個(gè)相同,但是不依賴于event_struct.h中的event結(jié)構(gòu)體的大小,而是使用event_get_struct_size()來(lái)獲取運(yùn)行時(shí)的正確大小。

            示例

            #include <event2/event.h>
            #include 
            <stdlib.h>

            /* When we allocate an event_pair in memory, we'll actually allocate
             * more space at the end of the structure.  We define some macros
             * to make accessing those events less error-prone. 
            */
            struct event_pair {
                     evutil_socket_t fd;
            };

            /* Macro: yield the struct event 'offset' bytes from the start of 'p' */
            #define EVENT_AT_OFFSET(p, offset) \
                        ((
            struct event*) ( ((char*)(p)) + (offset) ))
            /* Macro: yield the read event of an event_pair */
            #define READEV_PTR(pair) \
                        EVENT_AT_OFFSET((pair), 
            sizeof(struct event_pair))
            /* Macro: yield the write event of an event_pair */
            #define WRITEEV_PTR(pair) \
                        EVENT_AT_OFFSET((pair), \
                            
            sizeof(struct event_pair)+event_get_struct_event_size())

            /* Macro: yield the actual size to allocate for an event_pair */
            #define EVENT_PAIR_SIZE() \
                        (
            sizeof(struct event_pair)+2*event_get_struct_event_size())

            void readcb(evutil_socket_t, shortvoid *);
            void writecb(evutil_socket_t, shortvoid *);
            struct event_pair *event_pair_new(struct event_base *base, evutil_socket_t fd)
            {
                    
            struct event_pair *= malloc(EVENT_PAIR_SIZE());
                    
            if (!p) return NULL;
                    p
            ->fd = fd;
                    event_assign(READEV_PTR(p), 
            base, fd, EV_READ|EV_PERSIST, readcb, p);
                    event_assign(WRITEEV_PTR(p), 
            base, fd, EV_WRITE|EV_PERSIST, writecb, p);
                    
            return p;
            }

            event_assign()定義在<event2/event.h>中,從2.0.1-alpha版本開(kāi)始就存在了。從2.0.3-alpha版本開(kāi)始,函數(shù)返回int,在這之前函數(shù)返回void。event_get_struct_event_size()在2.0.4-alpha版本中引入。event結(jié)構(gòu)體定義在<event2/event_struct.h>中。

            讓事件未決和非未決

            構(gòu)造事件之后,在將其添加到event_base之前實(shí)際上是不能對(duì)其做任何操作的。使用event_add()將事件添加到event_base。

            接口

            int event_add(struct event *ev, const struct timeval *tv);

            在非未決的事件上調(diào)用event_add()將使其在配置的event_base中成為未決的。成功時(shí)函數(shù)返回0,失敗時(shí)返回-1。如果tv為NULL,添加的事件不會(huì)超時(shí)。否則,tv以秒和微秒指定超時(shí)值。

            如果對(duì)已經(jīng)未決的事件調(diào)用event_add(),事件將保持未決狀態(tài),并在指定的超時(shí)時(shí)間被重新調(diào)度。

            注意:不要設(shè)置tv為希望超時(shí)事件執(zhí)行的時(shí)間。如果在2010年1月1日設(shè)置“tv->tv_sec=time(NULL)+10;”,超時(shí)事件將會(huì)等待40年,而不是10秒。

            接口

            int event_del(struct event *ev);

            對(duì)已經(jīng)初始化的事件調(diào)用event_del()將使其成為非未決和非激活的。如果事件不是未決的或者激活的,調(diào)用將沒(méi)有效果。成功時(shí)函數(shù)返回0,失敗時(shí)返回-1。

            注意:如果在事件激活后,其回調(diào)被執(zhí)行前刪除事件,回調(diào)將不會(huì)執(zhí)行。

            這些函數(shù)定義在<event2/event.h>中,從0.1版本就存在了。

            帶優(yōu)先級(jí)的事件

            多個(gè)事件同時(shí)觸發(fā)時(shí),libevent沒(méi)有定義各個(gè)回調(diào)的執(zhí)行次序。可以使用優(yōu)先級(jí)來(lái)定義某些事件比其他事件更重要。

            在前一章討論過(guò),每個(gè)event_base有與之相關(guān)的一個(gè)或者多個(gè)優(yōu)先級(jí)。在初始化事件之后,但是在添加到event_base之前,可以為其設(shè)置優(yōu)先級(jí)。

            接口

            int event_priority_set(struct event *eventint priority);

            事件的優(yōu)先級(jí)是一個(gè)在0和event_base的優(yōu)先級(jí)減去1之間的數(shù)值。成功時(shí)函數(shù)返回0,失敗時(shí)返回-1。

            多個(gè)不同優(yōu)先級(jí)的事件同時(shí)成為激活的時(shí)候,低優(yōu)先級(jí)的事件不會(huì)運(yùn)行。libevent會(huì)執(zhí)行高優(yōu)先級(jí)的事件,然后重新檢查各個(gè)事件。只有在沒(méi)有高優(yōu)先級(jí)的事件是激活的時(shí)候,低優(yōu)先級(jí)的事件才會(huì)運(yùn)行。

            示例

            #include <event2/event.h>

            void read_cb(evutil_socket_t, shortvoid *);
            void write_cb(evutil_socket_t, shortvoid *);

            void main_loop(evutil_socket_t fd)
            {
              
            struct event *important, *unimportant;
              
            struct event_base *base;

              
            base = event_base_new();
              event_base_priority_init(
            base2);
              
            /* Now base has priority 0, and priority 1 */
              important 
            = event_new(base, fd, EV_WRITE|EV_PERSIST, write_cb, NULL);
              unimportant 
            = event_new(base, fd, EV_READ|EV_PERSIST, read_cb, NULL);
              event_priority_set(important, 
            0);
              event_priority_set(unimportant, 
            1);

              
            /* Now, whenever the fd is ready for writing, the write callback will
                 happen before the read callback.  The read callback won't happen at
                 all until the write callback is no longer active. 
            */
            }

            如果不為事件設(shè)置優(yōu)先級(jí),則默認(rèn)的優(yōu)先級(jí)將會(huì)是event_base的優(yōu)先級(jí)數(shù)目除以2。

            這個(gè)函數(shù)聲明在<event2/event.h>中,從1.0版本就存在了。

            檢查事件狀態(tài)

            有時(shí)候需要了解事件是否已經(jīng)添加,檢查事件代表什么。

            接口

            int event_pending(const struct event *ev, short what, struct timeval *tv_out);

            #define event_get_signal(ev) /*  */
            evutil_socket_t event_get_fd(
            const struct event *ev);
            struct event_base *event_get_base(const struct event *ev);
            short event_get_events(const struct event *ev);
            event_callback_fn event_get_callback(
            const struct event *ev);
            void *event_get_callback_arg(const struct event *ev);
            int event_get_priority(const struct event *ev);

            void event_get_assignment(const struct event *event,
                    
            struct event_base **base_out,
                    evutil_socket_t 
            *fd_out,
                    
            short *events_out,
                    event_callback_fn 
            *callback_out,
                    
            void **arg_out);

            event_pending()函數(shù)確定給定的事件是否是未決的或者激活的。如果是,而且what參數(shù)設(shè)置了EV_READ、EV_WRITE、EV_SIGNAL或者EV_TIMEOUT等標(biāo)志,則函數(shù)會(huì)返回事件當(dāng)前為之未決或者激活的所有標(biāo)志。如果提供了tv_out參數(shù),并且what參數(shù)中設(shè)置了EV_TIMEOUT標(biāo)志,而事件當(dāng)前正因超時(shí)事件而未決或者激活,則tv_out會(huì)返回事件的超時(shí)值。

            event_get_fd()和event_get_signal()返回為事件配置的文件描述符或者信號(hào)值。event_get_base()返回為事件配置的event_base。event_get_events()返回事件的標(biāo)志(EV_READ、EV_WRITE等)。event_get_callback()和event_get_callback_arg()返回事件的回調(diào)函數(shù)及其參數(shù)指針。

            event_get_assignment()復(fù)制所有為事件分配的字段到提供的指針中。任何為NULL的參數(shù)會(huì)被忽略。

            示例

            #include <event2/event.h>
            #include 
            <stdio.h>

            /* Change the callback and callback_arg of 'ev', which must not be
             * pending. 
            */
            int replace_callback(struct event *ev, event_callback_fn new_callback,
                
            void *new_callback_arg)
            {
                
            struct event_base *base;
                evutil_socket_t fd;
                
            short events;

                
            int pending;

                pending 
            = event_pending(ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT,
                                        NULL);
                
            if (pending) {
                    
            /* We want to catch this here so that we do not re-assign a
                     * pending event.  That would be very very bad. 
            */
                    fprintf(stderr,
                            
            "Error! replace_callback called on a pending event!\n");
                    
            return -1;
                }

                event_get_assignment(ev, 
            &base&fd, &events,
                                     NULL 
            /* ignore old callback */ ,
                                     NULL 
            /* ignore old callback argument */);

                event_assign(ev, 
            base, fd, events, new_callback, new_callback_arg);
                
            return 0;
            }

            這些函數(shù)聲明在<event2/event.h>中。event_pending()函數(shù)從0.1版就存在了。2.0.1-alpha版引入了event_get_fd()和event_get_signal()。2.0.2-alpha引入了event_get_base()。其他的函數(shù)在2.0.4-alpha版中引入。

            配置一次觸發(fā)事件

            如果不需要多次添加一個(gè)事件,或者要在添加后立即刪除事件,而事件又不需要是持久的,則可以使用event_base_once()。

            接口

            int event_base_once(struct event_base *, evutil_socket_t, short,
              
            void (*)(evutil_socket_t, shortvoid *), void *const struct timeval *);

            除了不支持EV_SIGNAL或者EV_PERSIST之外,這個(gè)函數(shù)的接口與event_new()相同。安排的事件將以默認(rèn)的優(yōu)先級(jí)加入到event_base并執(zhí)行。回調(diào)被執(zhí)行后,libevent內(nèi)部將會(huì)釋放event結(jié)構(gòu)。成功時(shí)函數(shù)返回0,失敗時(shí)返回-1。

            不能刪除或者手動(dòng)激活使用event_base_once()插入的事件:如果希望能夠取消事件,應(yīng)該使用event_new()或者event_assign()。

            手動(dòng)激活事件

            極少數(shù)情況下,需要在事件的條件沒(méi)有觸發(fā)的時(shí)候讓事件成為激活的。

            接口

            void event_active(struct event *ev, int what, short ncalls);

            這個(gè)函數(shù)讓事件ev帶有標(biāo)志what(EV_READ、EV_WRITE和EV_TIMEOUT的組合)成為激活的。事件不需要已經(jīng)處于未決狀態(tài),激活事件也不會(huì)讓它成為未決的。

            這個(gè)函數(shù)定義在<event2/event.h>中,從0.3版本就存在了。

            優(yōu)化公用超時(shí)

            當(dāng)前版本的libevent使用二進(jìn)制堆算法跟蹤未決事件的超時(shí)值,這讓添加和刪除事件超時(shí)值具有O(logN)性能。對(duì)于隨機(jī)分布的超時(shí)值集合,這是優(yōu)化的,但對(duì)于大量具有相同超時(shí)值的事件集合,則不是。

            比如說(shuō),假定有10000個(gè)事件,每個(gè)都需要在添加后5秒觸發(fā)超時(shí)事件。這種情況下,使用雙鏈隊(duì)列實(shí)現(xiàn)才可以取得O(1)性能。

            自然地,不希望為所有超時(shí)值使用隊(duì)列,因?yàn)殛?duì)列僅對(duì)常量超時(shí)值更快。如果超時(shí)值或多或少地隨機(jī)分布,則向隊(duì)列添加超時(shí)值的性能將是O(n),這顯然比使用二進(jìn)制堆糟糕得多。

            libevent通過(guò)放置一些超時(shí)值到隊(duì)列中,另一些到二進(jìn)制堆中來(lái)解決這個(gè)問(wèn)題。要使用這個(gè)機(jī)制,需要向libevent請(qǐng)求一個(gè)“公用超時(shí)(common timeout)”值,然后使用它來(lái)添加事件。如果有大量具有單個(gè)公用超時(shí)值的事件,使用這個(gè)優(yōu)化應(yīng)該可以改進(jìn)超時(shí)處理性能。

            接口

            const struct timeval *event_base_init_common_timeout(
                
            struct event_base *baseconst struct timeval *duration);

            這個(gè)函數(shù)需要event_base和要初始化的公用超時(shí)值作為參數(shù)。函數(shù)返回一個(gè)到特別的timeval結(jié)構(gòu)體的指針,可以使用這個(gè)指針指示事件應(yīng)該被添加到O(1)隊(duì)列,而不是O(logN)堆。可以在代碼中自由地復(fù)制這個(gè)特別的timeval或者進(jìn)行賦值,但它僅對(duì)用于構(gòu)造它的特定event_base有效。不能依賴于其實(shí)際內(nèi)容:libevent使用這個(gè)內(nèi)容來(lái)告知自身使用哪個(gè)隊(duì)列。

            示例

            #include <event2/event.h>
            #include 
            <string.h>

            /* We're going to create a very large number of events on a given base,
             * nearly all of which have a ten-second timeout.  If initialize_timeout
             * is called, we'll tell Libevent to add the ten-second ones to an O(1)
             * queue. 
            */
            struct timeval ten_seconds = { 100 };

            void initialize_timeout(struct event_base *base)
            {
                
            struct timeval tv_in = { 100 };
                
            const struct timeval *tv_out;
                tv_out 
            = event_base_init_common_timeout(base&tv_in);
                memcpy(
            &ten_seconds, tv_out, sizeof(struct timeval));
            }

            int my_event_add(struct event *ev, const struct timeval *tv)
            {
                
            /* Note that ev must have the same event_base that we passed to
                   initialize_timeout 
            */
                
            if (tv && tv->tv_sec == 10 && tv->tv_usec == 0)
                    
            return event_add(ev, &ten_seconds);
                
            else
                    
            return event_add(ev, tv);
            }

            與所有優(yōu)化函數(shù)一樣,除非確信適合使用,應(yīng)該避免使用公用超時(shí)功能。

            這個(gè)函數(shù)由2.0.4-alpha版本引入。

            從已清除的內(nèi)存識(shí)別事件

            libevent提供了函數(shù),可以從已經(jīng)通過(guò)設(shè)置為0(比如說(shuō),通過(guò)calloc()分配的,或者使用memset()或者bzero()清除了的)而清除的內(nèi)存識(shí)別出已初始化的事件。

            接口

            int event_initialized(const struct event *ev);

            #define evsignal_initialized(ev) event_initialized(ev)
            #define evtimer_initialized(ev) event_initialized(ev)

            警告

            這個(gè)函數(shù)不能可靠地從沒(méi)有初始化的內(nèi)存塊中識(shí)別出已經(jīng)初始化的事件。除非知道被查詢的內(nèi)存要么是已清除的,要么是已經(jīng)初始化為事件的,才能使用這個(gè)函數(shù)。

            除非編寫(xiě)一個(gè)非常特別的應(yīng)用,通常不需要使用這個(gè)函數(shù)。event_new()返回的事件總是已經(jīng)初始化的。

            示例

            #include <event2/event.h>
            #include 
            <stdlib.h>

            struct reader {
                evutil_socket_t fd;
            };

            #define READER_ACTUAL_SIZE() \
                (
            sizeof(struct reader) + \
                 event_get_struct_event_size())

            #define READER_EVENT_PTR(r) \
                ((
            struct event *) (((char*)(r))+sizeof(struct reader)))

            struct reader *allocate_reader(evutil_socket_t fd)
            {
                
            struct reader *= calloc(1, READER_ACTUAL_SIZE());
                
            if (r)
                    r
            ->fd = fd;
                
            return r;
            }

            void readcb(evutil_socket_t, shortvoid *);
            int add_reader(struct reader *r, struct event_base *b)
            {
                
            struct event *ev = READER_EVENT_PTR(r);
                
            if (!event_initialized(ev))
                    event_assign(ev, b, r
            ->fd, EV_READ, readcb, r);
                
            return event_add(ev, NULL);
            }

            event_initialized()函數(shù)從0.3版本就存在了。

            廢棄的事件操作函數(shù)

            2.0版本之前的libevent沒(méi)有event_assign()或者event_new()。替代的是將事件關(guān)聯(lián)到“當(dāng)前”event_base的event_set()。如果有多個(gè)event_base,需要記得調(diào)用event_base_set()來(lái)確定事件確實(shí)是關(guān)聯(lián)到當(dāng)前使用的event_base的。

            接口

            void event_set(struct event *event, evutil_socket_t fd, short what,
                    
            void(*callback)(evutil_socket_t, shortvoid *), void *arg);
            int event_base_set(struct event_base *basestruct event *event);

            除了使用當(dāng)前event_base之外,event_set()跟event_assign()是相似的。event_base_set()用于修改事件所關(guān)聯(lián)到的event_base。

            event_set()具有一些用于更方便地處理定時(shí)器和信號(hào)的變體:evtimer_set()大致對(duì)應(yīng)evtimer_assign();evsignal_set()大致對(duì)應(yīng)evsignal_assign()。

            2.0版本之前的libevent使用“signal_”作為用于信號(hào)的event_set()等函數(shù)變體的前綴,而不是“evsignal_”(也就是說(shuō),有signal_set()、signal_add()、signal_del()、signal_pending()和signal_initialized())。遠(yuǎn)古版本(0.6版之前)的libevent使用“timeout_”而不是“evtimer_”。因此,做代碼考古(code archeology)(注:這個(gè)翻譯似乎不正確,是否有更專業(yè)的術(shù)語(yǔ)?比如說(shuō),“代碼復(fù)審”)時(shí)可能會(huì)看到timeout_add()、timeout_del()、timeout_initialized()、timeout_set()和timeout_pending()等等。

            較老版本(2.0版之前)的libevent用宏EVENT_FD()和EVENT_SIGNAL()代表現(xiàn)在的event_get_fd()和event_get_signal()函數(shù)。這兩個(gè)宏直接檢查event結(jié)構(gòu)體的內(nèi)容,所以會(huì)妨礙不同版本之間的二進(jìn)制兼容性。在2.0以及后續(xù)版本中,這兩個(gè)宏僅僅是event_get_fd()和event_get_signal()的別名。

            因?yàn)?.0之前的版本不支持鎖,所以在運(yùn)行event_base的線程之外的任何線程調(diào)用修改事件狀態(tài)的函數(shù)都是不安全的。這些函數(shù)包括event_add()、event_del()、event_active()和event_base_once()。

            有一個(gè)event_once()與event_base_once()相似,只是用于當(dāng)前event_base。

            2.0版本之前EV_PERSIST標(biāo)志不能正確地操作超時(shí)。標(biāo)志不會(huì)在事件激活時(shí)復(fù)位超時(shí)值,而是沒(méi)有任何操作。

            2.0之前的版本不支持同時(shí)添加多個(gè)帶有相同fd和READ/WRITE標(biāo)志的事件。也就是說(shuō),在每個(gè)fd上,某時(shí)刻只能有一個(gè)事件等待讀取,也只能有一個(gè)事件等待寫(xiě)入。



            亚洲国产精品无码久久98| 久久精品视频免费| 综合久久国产九一剧情麻豆 | 国产精品va久久久久久久| 99久久99久久精品国产片| 欧美午夜A∨大片久久 | 国内精品久久久久伊人av| 狠狠久久综合| 久久久久成人精品无码中文字幕 | 少妇久久久久久久久久| 91亚洲国产成人久久精品网址| 精品久久久久久久国产潘金莲 | 国内精品伊人久久久久av一坑| 久久av高潮av无码av喷吹| 亚洲午夜无码久久久久| 欧美粉嫩小泬久久久久久久| 91精品国产色综合久久| 久久人做人爽一区二区三区| 久久国产精品国语对白| 久久免费小视频| 久久综合狠狠综合久久综合88| 亚洲中文字幕伊人久久无码| 国产精品va久久久久久久| 99久久99久久精品国产| 久久国产乱子伦精品免费强| 99久久er这里只有精品18| 亚洲va中文字幕无码久久不卡| 伊人久久大香线蕉成人| 久久996热精品xxxx| 久久久精品国产Sm最大网站| 一本伊大人香蕉久久网手机| 久久久久国产一级毛片高清版| 久久九九精品99国产精品| 亚洲欧洲日产国码无码久久99| 久久久网中文字幕| 色天使久久综合网天天| 中文字幕久久精品 | 伊人色综合久久天天网| 久久91精品国产91久| 久久久精品人妻一区二区三区蜜桃| 久久久久久午夜成人影院|