4 鎖和線程windows
編寫多線程程序的時候,在多個線程中同時訪問一樣的數據並不老是安全的。api
libevent的結構體在多線程下一般有三種工做方式:安全
² 某些結構體內在地是單線程的:同時在多個線程中使用它們老是不安全的。多線程
² 某些結構體具備可選的鎖:能夠告知libevent是否須要在多個線程中使用每一個對象。socket
² 某些結構體老是鎖定的:若是libevent在支持鎖的配置下運行,在多個線程中使用它們老是安全的。ide
爲獲取鎖,在調用分配須要在多個線程間共享的結構體的libevent函數以前,必須告知libevent使用哪一個鎖函數。函數
若是使用pthreads庫,或者使用Windows本地線程代碼,那麼你是幸運的:已經有設置好的libevent預約義函數可以正確的使用pthreads或者Windows函數。oop
這些函數在成功時都返回0,失敗時返回-1。ui
若是使用不一樣的線程庫,則須要一些額外的工做,必須使用你的線程庫來定義函數去實現:spa
l 鎖
l 鎖定
l 解鎖
l 分配鎖
l 析構鎖
l 條件變量
l 建立條件變量
l 析構條件變量
l 等待條件變量
l 觸發/廣播某條件變量
l 線程
l 線程ID檢測
使用evthread_set_lock_callbacks和evthread_set_id_callback接口告知libevent這些函數。
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,不然返回非零。
0:一般的,沒必要遞歸的鎖。
EVTHREAD_LOCKTYPE_RECURSIVE:不會阻塞已經持有它的線程的鎖。一旦持有它的線程進行原來鎖定次數的解鎖,其餘線程馬上就能夠請求它了。
EVTHREAD_LOCKTYPE_READWRITE:可讓多個線程同時由於讀而持有它,可是任什麼時候刻只有一個線程由於寫而持有它。寫操做排斥全部讀操做。
EVTHREAD_READ:僅用於讀寫鎖:爲讀操做請求或者釋放鎖
EVTHREAD_WRITE:僅用於讀寫鎖:爲寫操做請求或者釋放鎖
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。這時候已建立的使用上述線程相關函數的程序將不能運行。
爲幫助調試鎖的使用,libevent有一個可選的「鎖調試」特徵。這個特徵包裝了鎖調用,以便捕獲典型的鎖錯誤,包括:
l 解並無真正持有的鎖。
l 從新鎖定一個非遞歸鎖。
若是發生這些錯誤中的某一個,libevent將給出斷言失敗而且退出。
void evthread_enable_lock_debuging(void);
必須在建立或者使用任何鎖以前調用這個函數。爲安全起見,請在設置完線程函數後當即調用這個函數。
這個函數是在2.0.4-alpha版本新引入的。
libevent能夠檢測使用事件時的一些常見錯誤而且進行報告。這些錯誤包括:
l 將未初始化的event結構體看成已經初始化的。
l 試圖從新初始化一個掛起的event結構體。
跟蹤哪些事件已經初始化須要使用額外的內存和處理器時間,因此只應該在真正調試程序的時候才啓用調試模式。
void event_enable_debug_mode(void);
必須在建立任何event_base以前調用這個函數。
若是在調試模式下使用大量由event_assign()(而不是event_new())建立的事件,程序可能會耗盡內存,這是由於沒有方式能夠告知libevent由event_assign()建立的事件不會再被使用了(能夠調用event_free()告知由event_new()建立的事件已經無效了)。若是想在調試時避免耗盡內存,能夠顯式告知libevent由event_assign()建立的這些事件再也不被看成已分配的了:
void event_debug_unassign(struct event *ev);
沒有啓用調試的時候調用event_debug_unassign沒有效果。
這些調試函數在libevent 2.0.4-alpha版本中加入。
新版本的libevent會添加特徵,移除bug。有時候須要檢測libevent的版本,以便:
l 檢測已安裝的libevent版本是否可用於建立你的程序。
l 爲調試顯示libevent的版本。
l 檢測libevent的版本,以便向用戶警告bug,或者提示要作的工做。
宏返回編譯時的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。
本節描述的宏和函數定義在<event2/event.h>中。event_get_version函數首次出如今1.0c版本;其餘的首次出如今2.0.1-alpha版本。