• <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/Ref1_libsetup.html
            轉(zhuǎn)自
            http://blog.sina.com.cn/s/blog_56dee71a0100q9ks.html

            libevent有一些被整個進(jìn)程共享的、影響整個庫的全局設(shè)置。必須在調(diào)用libevent庫的任何其他部分之前修改這些設(shè)置,否則,libevent會進(jìn)入不一致的狀態(tài)。

            1 Libevent中的日志消息

            libevent可以記錄內(nèi)部錯誤和警告。如果編譯進(jìn)日志支持,還會記錄調(diào)試信息。默認(rèn)配置下這些信息被寫到stderr。通過提供定制的日志函數(shù)可以覆蓋默認(rèn)行為。

            接口
            #define EVENT_LOG_DEBUG 0
            #define EVENT_LOG_MSG   1
            #define EVENT_LOG_WARN  2
            #define EVENT_LOG_ERR   3

            /* Deprecated; see note at the end of this section */
            #define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG
            #define _EVENT_LOG_MSG   EVENT_LOG_MSG
            #define _EVENT_LOG_WARN  EVENT_LOG_WARN
            #define _EVENT_LOG_ERR   EVENT_LOG_ERR

            typedef 
            void (*event_log_cb)(int severity, const char *msg);

            void event_set_log_callback(event_log_cb cb);

            要覆蓋libevent的日志行為,編寫匹配event_log_cb簽名的定制函數(shù),將其作為參數(shù)傳遞給event_set_log_callback()。隨后libevent在日志信息的時候,將會把信息傳遞給你提供的函數(shù)。再次調(diào)用event_set_log_callback(),傳遞參數(shù)NULL,就可以恢復(fù)默認(rèn)行為。

            示例

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

            static void discard_cb(int severity, const char *msg)
            {
                
            /* This callback does nothing. */
            }

            static FILE *logfile = NULL;
            static void write_to_file_cb(int severity, const char *msg)
            {
                
            const char *s;
                
            if (!logfile)
                    
            return;
                
            switch (severity) {
                    
            case _EVENT_LOG_DEBUG: s = "debug"break;
                    
            case _EVENT_LOG_MSG:   s = "msg";   break;
                    
            case _EVENT_LOG_WARN:  s = "warn";  break;
                    
            case _EVENT_LOG_ERR:   s = "error"break;
                    
            default:               s = "?";     break/* never reached */
                }
                fprintf(logfile, 
            "[%s] %s\n", s, msg);
            }

            /* Turn off all logging from Libevent. */
            void suppress_logging(void)
            {
                event_set_log_callback(discard_cb);
            }

            /* Redirect all Libevent log messages to the C stdio file 'f'. */
            void set_logfile(FILE *f)
            {
                logfile 
            = f;
                event_set_log_callback(write_to_file_cb);
            }

            注意

            在用戶提供的event_log_cb回調(diào)函數(shù)中調(diào)用libevent函數(shù)是不安全的。比如說,如果試圖編寫一個使用bufferevent將警告信息發(fā)送給某個套接字的日志回調(diào)函數(shù),可能會遇到奇怪而難以診斷的bug。未來版本libevent的某些函數(shù)可能會移除這個限制。

            這個函數(shù)在<event2/event.h>中聲明,在libevent 1.0c版本中首次出現(xiàn)。

            2 處理致命錯誤

            libevent在檢測到不可恢復(fù)的內(nèi)部錯誤時的默認(rèn)行為是調(diào)用exit()或者abort(),退出正在運行的進(jìn)程。這類錯誤通常意味著某處有bug:要么在你的代碼中,要么在libevent中。

            如果希望更優(yōu)雅地處理致命錯誤,可以為libevent提供在退出時應(yīng)該調(diào)用的函數(shù),覆蓋默認(rèn)行為。

            接口

            typedef void (*event_fatal_cb)(int err);
            void event_set_fatal_callback(event_fatal_cb cb);

            要使用這些函數(shù),首先定義libevent在遇到致命錯誤時應(yīng)該調(diào)用的函數(shù),將其傳遞給event_set_fatal_callback()。隨后libevent在遇到致命錯誤時將調(diào)用你提供的函數(shù)。

            你的函數(shù)不應(yīng)該將控制返回到libevent:這樣做可能導(dǎo)致不確定的行為。為了避免崩潰,libevent還是會退出。你的函數(shù)被不應(yīng)該調(diào)用其它libevent函數(shù)。

            這些函數(shù)聲明在<event2/event.h>中,在libevent 2.0.3-alpha版本中首次出現(xiàn)。

            3 內(nèi)存管理

            默認(rèn)情況下,libevent使用C庫的內(nèi)存管理函數(shù)在堆上分配內(nèi)存。通過提供malloc、realloc和free的替代函數(shù),可以讓libevent使用其他的內(nèi)存管理器。希望libevent使用一個更高效的分配器時;或者希望libevent使用一個工具分配器,以便檢查內(nèi)存泄漏時,可能需要這樣做。

            接口

            void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
                                         
            void *(*realloc_fn)(void *ptr, size_t sz),
                                         
            void (*free_fn)(void *ptr));
            這里有個替換libevent分配器函數(shù)的示例,它可以計算已經(jīng)分配的字節(jié)數(shù)。實際應(yīng)用中可能需要添加鎖,以避免運行在多個線程中時發(fā)生錯誤。

            示例

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

            /* This union's purpose is to be as big as the largest of all the
             * types it contains. 
            */
            union alignment {
                size_t sz;
                
            void *ptr;
                
            double dbl;
            };
            /* We need to make sure that everything we return is on the right
               alignment to hold anything, including a double. 
            */
            #define ALIGNMENT sizeof(union alignment)

            /* We need to do this cast-to-char* trick on our pointers to adjust
               them; doing arithmetic on a void* is not standard. 
            */
            #define OUTPTR(ptr) (((char*)ptr)+ALIGNMENT)
            #define INPTR(ptr) (((char*)ptr)-ALIGNMENT)

            static size_t total_allocated = 0;
            static void *replacement_malloc(size_t sz)
            {
                
            void *chunk = malloc(sz + ALIGNMENT);
                
            if (!chunk) return chunk;
                total_allocated 
            += sz;
                
            *(size_t*)chunk = sz;
                
            return OUTPTR(chunk);
            }
            static void *replacement_realloc(void *ptr, size_t sz)
            {
                size_t old_size 
            = 0;
                
            if (ptr) {
                    ptr 
            = INPTR(ptr);
                    old_size 
            = *(size_t*)ptr;
                }
                ptr 
            = realloc(ptr, sz + ALIGNMENT);
                
            if (!ptr)
                    
            return NULL;
                
            *(size_t*)ptr = sz;
                total_allocated 
            = total_allocated - old_size + sz;
                
            return OUTPTR(ptr);
            }
            static void replacement_free(void *ptr)
            {
                ptr 
            = INPTR(ptr);
                total_allocated 
            -= *(size_t*)ptr;
                free(ptr);
            }
            void start_counting_bytes(void)
            {
                event_set_mem_functions(replacement_malloc,
                                        replacement_realloc,
                                        replacement_free);
            }

            注意

            v 替換內(nèi)存管理函數(shù)影響libevent隨后的所有分配、調(diào)整大小和釋放內(nèi)存操作。所以,必須保證在調(diào)用任何其他libevent函數(shù)之前進(jìn)行替換。否則,libevent可能用你的free函數(shù)釋放用C庫的malloc分配的內(nèi)存。

            v 你的malloc和realloc函數(shù)返回的內(nèi)存塊應(yīng)該具有和C庫返回的內(nèi)存塊一樣的地址對齊。

            v 你的realloc函數(shù)應(yīng)該正確處理realloc(NULL,sz)(也就是當(dāng)作malloc(sz)處理)

            v 你的realloc函數(shù)應(yīng)該正確處理realloc(ptr,0)(也就是當(dāng)作free(ptr)處理)

            v 你的free函數(shù)不必處理free(NULL)

            v 你的malloc函數(shù)不必處理malloc(0)

            v 如果在多個線程中使用libevent,替代的內(nèi)存管理函數(shù)需要是線程安全的。

            v libevent將使用這些函數(shù)分配返回給你的內(nèi)存。所以,如果要釋放由libevent函數(shù)分配和返回的內(nèi)存,而你已經(jīng)替換malloc和realloc函數(shù),那么應(yīng)該使用替代的free函數(shù)。

             

            event_set_mem_functions函數(shù)聲明在<event2/event.h>中,在libevent 2.0.1-alpha版本中首次出現(xiàn)。

            可以在禁止event_set_mem_functions函數(shù)的配置下編譯libevent。這時候使用event_set_mem_functions將不會編譯或者鏈接。在2.0.2-alpha及以后版本中,可以通過檢查是否定義了EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED宏來確定event_set_mem_functions函數(shù)是否存在。

            4 鎖和線程

            編寫多線程程序的時候,在多個線程中同時訪問同樣的數(shù)據(jù)并不總是安全的。

            libevent的結(jié)構(gòu)體在多線程下通常有三種工作方式:

            v 某些結(jié)構(gòu)體內(nèi)在地是單線程的:同時在多個線程中使用它們總是不安全的。

            v 某些結(jié)構(gòu)體具有可選的鎖:可以告知libevent是否需要在多個線程中使用每個對象。

            v 某些結(jié)構(gòu)體總是鎖定的:如果libevent在支持鎖的配置下運行,在多個線程中使用它們總是安全的。

            為獲取鎖,在調(diào)用分配需要在多個線程間共享的結(jié)構(gòu)體的libevent函數(shù)之前,必須告知libevent使用哪個鎖函數(shù)。

            如果使用pthreads庫,或者使用Windows本地線程代碼,那么你是幸運的:已經(jīng)有設(shè)置libevent使用正確的pthreads或者Windows函數(shù)的預(yù)定義函數(shù)。

            接口

            #ifdef WIN32
            int evthread_use_windows_threads(void);
            #define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
            #endif
            #ifdef _EVENT_HAVE_PTHREADS
            int evthread_use_pthreads(void);
            #define EVTHREAD_USE_PTHREADS_IMPLEMENTED
            #endif

            這些函數(shù)在成功時都返回0,失敗時返回-1。

            如果使用不同的線程庫,則需要一些額外的工作,必須使用你的線程庫來定義函數(shù)去實現(xiàn):

            v 

            v 鎖定

            v 解鎖

            v 分配鎖

            v 析構(gòu)鎖

            v 條件變量

            v 創(chuàng)建條件變量

            v 析構(gòu)條件變量

            v 等待條件變量

            v 觸發(fā)/廣播某條件變量

            v 線程

            v 線程ID檢測

            使用evthread_set_lock_callbacks和evthread_set_id_callback接口告知libevent這些函數(shù)。

            接口

            #define EVTHREAD_WRITE  0x04
            #define EVTHREAD_READ   0x08
            #define EVTHREAD_TRY    0x10

            #define EVTHREAD_LOCKTYPE_RECURSIVE 1
            #define EVTHREAD_LOCKTYPE_READWRITE 2

            #define EVTHREAD_LOCK_API_VERSION 1

            struct evthread_lock_callbacks {
                   
            int lock_api_version;
                   unsigned supported_locktypes;
                   
            void *(*alloc)(unsigned locktype);
                   
            void (*free)(void *lock, unsigned locktype);
                   
            int (*lock)(unsigned mode, void *lock);
                   
            int (*unlock)(unsigned mode, void *lock);
            };

            int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);

            void evthread_set_id_callback(unsigned long (*id_fn)(void));

            struct evthread_condition_callbacks {
                    
            int condition_api_version;
                    
            void *(*alloc_condition)(unsigned condtype);
                    
            void (*free_condition)(void *cond);
                    
            int (*signal_condition)(void *cond, int broadcast);
                    
            int (*wait_condition)(void *cond, void *lock,
                        
            const struct timeval *timeout);
            };

            int evthread_set_condition_callbacks(
                    
            const struct evthread_condition_callbacks *);

            evthread_lock_callbacks結(jié)構(gòu)體描述的鎖回調(diào)函數(shù)及其能力。對于上述版本,lock_api_version字段必須設(shè)置為EVTHREAD_LOCK_API_VERSION。必須設(shè)置supported_locktypes字段為EVTHREAD_LOCKTYPE_*常量的組合以描述支持的鎖類型(在2.0.4-alpha版本中,EVTHREAD_LOCK_RECURSIVE是必須的,EVTHREAD_LOCK_READWRITE則沒有使用)。alloc函數(shù)必須返回指定類型的新鎖;free函數(shù)必須釋放指定類型鎖持有的所有資源;lock函數(shù)必須試圖以指定模式請求鎖定,如果成功則返回0,失敗則返回非零;unlock函數(shù)必須試圖解鎖,成功則返回0,否則返回非零。

            可識別的鎖類型有:

            v 0:通常的,不必遞歸的鎖。

            v EVTHREAD_LOCKTYPE_RECURSIVE:不會阻塞已經(jīng)持有它的線程的鎖。一旦持有它的線程進(jìn)行原來鎖定次數(shù)的解鎖,其他線程立刻就可以請求它了。

            v EVTHREAD_LOCKTYPE_READWRITE:可以讓多個線程同時因為讀而持有它,但是任何時刻只有一個線程因為寫而持有它。寫操作排斥所有讀操作。

            可識別的鎖模式有:

            v EVTHREAD_READ:僅用于讀寫鎖:為讀操作請求或者釋放鎖

            v EVTHREAD_WRITE:僅用于讀寫鎖:為寫操作請求或者釋放鎖

            v EVTHREAD_TRY:僅用于鎖定:僅在可以立刻鎖定的時候才請求鎖定

            id_fn參數(shù)必須是一個函數(shù),它返回一個無符號長整數(shù),標(biāo)識調(diào)用此函數(shù)的線程。對于相同線程,這個函數(shù)應(yīng)該總是返回同樣的值;而對于同時調(diào)用該函數(shù)的不同線程,必須返回不同的值。

            evthread_condition_callbacks結(jié)構(gòu)體描述了與條件變量相關(guān)的回調(diào)函數(shù)。對于上述版本,condition_api_version字段必須設(shè)置為EVTHREAD_CONDITION_API_VERSION。alloc_condition函數(shù)必須返回到新條件變量的指針。它接受0作為其參數(shù)。free_condition函數(shù)必須釋放條件變量持有的存儲器和資源。wait_condition函數(shù)要求三個參數(shù):一個由alloc_condition分配的條件變量,一個由你提供的evthread_lock_callbacks.alloc函數(shù)分配的鎖,以及一個可選的超時值。調(diào)用本函數(shù)時,必須已經(jīng)持有參數(shù)指定的鎖;本函數(shù)應(yīng)該釋放指定的鎖,等待條件變量成為授信狀態(tài),或者直到指定的超時時間已經(jīng)流逝(可選)。wait_condition應(yīng)該在錯誤時返回-1,條件變量授信時返回0,超時時返回1。返回之前,函數(shù)應(yīng)該確定其再次持有鎖。最后,signal_condition函數(shù)應(yīng)該喚醒等待該條件變量的某個線程(broadcast參數(shù)為false時),或者喚醒等待條件變量的所有線程(broadcast參數(shù)為true時)。只有在持有與條件變量相關(guān)的鎖的時候,才能夠進(jìn)行這些操作。

            關(guān)于條件變量的更多信息,請查看pthreads的pthread_cond_*函數(shù)文檔,或者Windows的CONDITION_VARIABLE(Windows Vista新引入的)函數(shù)文檔。

            示例

            關(guān)于使用這些函數(shù)的示例,請查看Libevent源代碼發(fā)布版本中的evthread_pthread.c和evthread_win32.c文件。

            這些函數(shù)在<event2/thread.h>中聲明,其中大多數(shù)在2.0.4-alpha版本中首次出現(xiàn)。2.0.1-alpha到2.0.3-alpha使用較老版本的鎖函數(shù)。event_use_pthreads函數(shù)要求程序鏈接到event_pthreads庫。

            條件變量函數(shù)是2.0.7-rc版本新引入的,用于解決某些棘手的死鎖問題。

            可以創(chuàng)建禁止鎖支持的libevent。這時候已創(chuàng)建的使用上述線程相關(guān)函數(shù)的程序?qū)⒉荒苓\行。

            5 調(diào)試鎖的使用

            為幫助調(diào)試鎖的使用,libevent有一個可選的“鎖調(diào)試”特征。這個特征包裝了鎖調(diào)用,以便捕獲典型的鎖錯誤,包括:

            v 解鎖并沒有持有的鎖

            v 重新鎖定一個非遞歸鎖

            如果發(fā)生這些錯誤中的某一個,libevent將給出斷言失敗并且退出。

            接口

            void evthread_enable_lock_debugging(void);
            #define evthread_enable_lock_debuging() evthread_enable_lock_debugging()

            注意

            必須在創(chuàng)建或者使用任何鎖之前調(diào)用這個函數(shù)。為安全起見,請在設(shè)置完線程函數(shù)后立即調(diào)用這個函數(shù)。

            這個函數(shù)是在2.0.4-alpha版本新引入的。

            6 調(diào)試事件的使用

            libevent可以檢測使用事件時的一些常見錯誤并且進(jìn)行報告。這些錯誤包括:

            v 將未初始化的event結(jié)構(gòu)體當(dāng)作已經(jīng)初始化的

            v 試圖重新初始化未決的event結(jié)構(gòu)體

            跟蹤哪些事件已經(jīng)初始化需要使用額外的內(nèi)存和處理器時間,所以只應(yīng)該在真正調(diào)試程序的時候才啟用調(diào)試模式。

            接口

            void event_enable_debug_mode(void);
            必須在創(chuàng)建任何event_base之前調(diào)用這個函數(shù)。

             

            如果在調(diào)試模式下使用大量由event_assign(而不是event_new)創(chuàng)建的事件,程序可能會耗盡內(nèi)存,這是因為沒有方式可以告知libevent由event_assign創(chuàng)建的事件不會再被使用了(可以調(diào)用event_free告知由event_new創(chuàng)建的事件已經(jīng)無效了)。如果想在調(diào)試時避免耗盡內(nèi)存,可以顯式告知libevent這些事件不再被當(dāng)作已分配的了:

            接口

            void event_debug_unassign(struct event *ev);

            沒有啟用調(diào)試的時候調(diào)用event_debug_unassign沒有效果。

            這些調(diào)試函數(shù)在libevent 2.0.4-alpha版本中加入。

            7 檢測libevent的版本

            新版本的libevent會添加特征,移除bug。有時候需要檢測libevent的版本,以便:

            v 檢測已安裝的libevent版本是否可用于創(chuàng)建你的程序

            v 為調(diào)試顯示libevent的版本

            v 檢測libevent的版本,以便向用戶警告bug,或者提示要做的工作

            接口
            #define LIBEVENT_VERSION_NUMBER 0x02000300
            #define LIBEVENT_VERSION "2.0.3-alpha"
            const char *event_get_version(void);
            ev_uint32_t event_get_version_number(
            void);

            宏返回編譯時的libevent版本;函數(shù)返回運行時的libevent版本。注意:如果動態(tài)鏈接到libevent,這兩個版本可能不同。

            可以獲取兩種格式的libevent版本:用于顯示給用戶的字符串版本,或者用于數(shù)值比較的4字節(jié)整數(shù)版本。整數(shù)格式使用高字節(jié)表示主版本,低字節(jié)表示副版本,第三字節(jié)表示修正版本,最低字節(jié)表示發(fā)布狀態(tài):0表示發(fā)布,非零表示某特定發(fā)布版本的后續(xù)開發(fā)序列。

            所以,libevent 2.0.1-alpha發(fā)布版本的版本號是[02 00 01 00],或者說0x02000100。2.0.1-alpha和2.0.2-alpha之間的開發(fā)版本可能是[02 00 01 08],或者說0x02000108。

            伊人久久综合热线大杳蕉下载| 国产精品午夜久久| 久久久久黑人强伦姧人妻| 久久综合一区二区无码| 亚洲七七久久精品中文国产| 久久久久久久波多野结衣高潮| 色综合久久无码五十路人妻| www.久久热| 中文字幕精品无码久久久久久3D日动漫| 国产精品久久久久久五月尺| 亚洲AV无码一区东京热久久| 久久久九九有精品国产| 一本综合久久国产二区| 996久久国产精品线观看| 久久久久久久综合日本| 久久ww精品w免费人成| 无码国内精品久久人妻麻豆按摩| 少妇精品久久久一区二区三区 | 久久综合精品国产一区二区三区| 欧美久久天天综合香蕉伊| 国内精品伊人久久久久AV影院| 色8激情欧美成人久久综合电| 99久久婷婷免费国产综合精品| 亚洲精品乱码久久久久久蜜桃| 久久精品国产一区二区三区日韩| 久久精品久久久久观看99水蜜桃| 国产精品成人99久久久久91gav | 久久影院亚洲一区| 青青热久久综合网伊人| 午夜精品久久久久久久| 亚洲欧美一区二区三区久久| 九九热久久免费视频| 国产精品一区二区久久| 久久精品国产亚洲AV嫖农村妇女| 日本高清无卡码一区二区久久| AA级片免费看视频久久| 麻豆精品久久久一区二区| 久久青青草原精品国产| 高清免费久久午夜精品| 久久99精品国产99久久6男男| 久久人人爽人人爽人人AV |