• <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
            轉自
            http://blog.sina.com.cn/s/blog_56dee71a0100q9ks.html

            libevent有一些被整個進程共享的、影響整個庫的全局設置。必須在調用libevent庫的任何其他部分之前修改這些設置,否則,libevent會進入不一致的狀態。

            1 Libevent中的日志消息

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

            接口
            #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簽名的定制函數,將其作為參數傳遞給event_set_log_callback()。隨后libevent在日志信息的時候,將會把信息傳遞給你提供的函數。再次調用event_set_log_callback(),傳遞參數NULL,就可以恢復默認行為。

            示例

            #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回調函數中調用libevent函數是不安全的。比如說,如果試圖編寫一個使用bufferevent將警告信息發送給某個套接字的日志回調函數,可能會遇到奇怪而難以診斷的bug。未來版本libevent的某些函數可能會移除這個限制。

            這個函數在<event2/event.h>中聲明,在libevent 1.0c版本中首次出現。

            2 處理致命錯誤

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

            如果希望更優雅地處理致命錯誤,可以為libevent提供在退出時應該調用的函數,覆蓋默認行為。

            接口

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

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

            你的函數不應該將控制返回到libevent:這樣做可能導致不確定的行為。為了避免崩潰,libevent還是會退出。你的函數被不應該調用其它libevent函數。

            這些函數聲明在<event2/event.h>中,在libevent 2.0.3-alpha版本中首次出現。

            3 內存管理

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

            接口

            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分配器函數的示例,它可以計算已經分配的字節數。實際應用中可能需要添加鎖,以避免運行在多個線程中時發生錯誤。

            示例

            #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 替換內存管理函數影響libevent隨后的所有分配、調整大小和釋放內存操作。所以,必須保證在調用任何其他libevent函數之前進行替換。否則,libevent可能用你的free函數釋放用C庫的malloc分配的內存。

            v 你的malloc和realloc函數返回的內存塊應該具有和C庫返回的內存塊一樣的地址對齊。

            v 你的realloc函數應該正確處理realloc(NULL,sz)(也就是當作malloc(sz)處理)

            v 你的realloc函數應該正確處理realloc(ptr,0)(也就是當作free(ptr)處理)

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

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

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

            v libevent將使用這些函數分配返回給你的內存。所以,如果要釋放由libevent函數分配和返回的內存,而你已經替換malloc和realloc函數,那么應該使用替代的free函數。

             

            event_set_mem_functions函數聲明在<event2/event.h>中,在libevent 2.0.1-alpha版本中首次出現。

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

            4 鎖和線程

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

            libevent的結構體在多線程下通常有三種工作方式:

            v 某些結構體內在地是單線程的:同時在多個線程中使用它們總是不安全的。

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

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

            為獲取鎖,在調用分配需要在多個線程間共享的結構體的libevent函數之前,必須告知libevent使用哪個鎖函數。

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

            接口

            #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

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

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

            v 

            v 鎖定

            v 解鎖

            v 分配鎖

            v 析構鎖

            v 條件變量

            v 創建條件變量

            v 析構條件變量

            v 等待條件變量

            v 觸發/廣播某條件變量

            v 線程

            v 線程ID檢測

            使用evthread_set_lock_callbacks和evthread_set_id_callback接口告知libevent這些函數。

            接口

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

            可識別的鎖類型有:

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

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

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

            可識別的鎖模式有:

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

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

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

            id_fn參數必須是一個函數,它返回一個無符號長整數,標識調用此函數的線程。對于相同線程,這個函數應該總是返回同樣的值;而對于同時調用該函數的不同線程,必須返回不同的值。

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

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

            示例

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

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

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

            可以創建禁止鎖支持的libevent。這時候已創建的使用上述線程相關函數的程序將不能運行。

            5 調試鎖的使用

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

            v 解鎖并沒有持有的鎖

            v 重新鎖定一個非遞歸鎖

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

            接口

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

            注意

            必須在創建或者使用任何鎖之前調用這個函數。為安全起見,請在設置完線程函數后立即調用這個函數。

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

            6 調試事件的使用

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

            v 將未初始化的event結構體當作已經初始化的

            v 試圖重新初始化未決的event結構體

            跟蹤哪些事件已經初始化需要使用額外的內存和處理器時間,所以只應該在真正調試程序的時候才啟用調試模式。

            接口

            void event_enable_debug_mode(void);
            必須在創建任何event_base之前調用這個函數。

             

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

            接口

            void event_debug_unassign(struct event *ev);

            沒有啟用調試的時候調用event_debug_unassign沒有效果。

            這些調試函數在libevent 2.0.4-alpha版本中加入。

            7 檢測libevent的版本

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

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

            v 為調試顯示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版本;函數返回運行時的libevent版本。注意:如果動態鏈接到libevent,這兩個版本可能不同。

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

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

            少妇内射兰兰久久| 欧美久久精品一级c片片| 久久久久成人精品无码| 国产精品热久久无码av| 亚洲欧美国产精品专区久久 | 久久黄色视频| 久久九九兔免费精品6| 久久久久久九九99精品| 国产精品VIDEOSSEX久久发布| 久久人搡人人玩人妻精品首页 | 色婷婷综合久久久久中文字幕 | 精品欧美一区二区三区久久久| 久久国产V一级毛多内射| 久久久久亚洲精品日久生情| 99久久精品国产高清一区二区| 久久国产乱子伦精品免费午夜| 亚洲伊人久久精品影院| 国产精品成人久久久久久久| 亚洲午夜久久久久久久久电影网| 国产精品一区二区久久| 99久久精品免费看国产一区二区三区| 国产成人精品白浆久久69| 午夜精品久久久久久影视777| 国产精品久久影院| 亚洲精品tv久久久久久久久| 久久久综合香蕉尹人综合网| 久久亚洲高清观看| 精品久久久久久亚洲精品 | 久久精品一本到99热免费| 久久精品九九亚洲精品天堂| 日韩av无码久久精品免费| 久久只有这里有精品4| 色天使久久综合网天天| 免费精品久久久久久中文字幕| 日本免费久久久久久久网站| 国产一级做a爰片久久毛片| 久久久久亚洲av无码专区| 日韩av无码久久精品免费| 久久AV高潮AV无码AV| 伊人久久综合成人网| 久久香蕉国产线看观看精品yw|