libevent文檔學習(一)多線程接口和使用

參考libevent官方提供的文檔: http://www.wangafu.net/~nickm/libevent-book/Ref1_libsetup.htmlhtml

這一篇主要翻譯libevent多線程的使用接口和文檔。linux

As you probably know if you’re writing multithreaded programs, it isn’t always safe to access the same data from multiple threads at the same time.windows

Libevent structures can generally work three ways with multithreading.api

  • Some structures are inherently single-threaded: it is never safe to use them from more than one thread at the same time.安全

  • Some structures are optionally locked: you can tell Libevent for each object whether you need to use it from multiple threads at once.多線程

  • Some structures are always locked: if Libevent is running with lock support, then they are always safe to use from multiple threads at once.ide

 

當你編寫多線程程序的時候,多個線程訪問同一塊數據並不安全。對於多線程libevent一般採起如下三種方式工做,函數

1 一些結構內不是單線程的,多線程同時訪問這個結構是不安全的。ui

2一些結構內部是選擇性加鎖的,你須要通知libevent,對於每一個對象你是否採用多線程的方式使用它。this

3一些結構老是加鎖的,若是libevent設置了加鎖的模式,採用多線程方式是安全的。

 

To get locking in Libevent, you must tell Libevent which locking functions to use. You need to do this before you call any Libevent function

that allocates a structure that needs to be shared between threads.

If you are using the pthreads library, or the native Windows threading code, you’re in luck. There are pre-defined functions that will set

Libevent up to use the right pthreads or Windows functions for you.

 

若是要使用libevent多線程鎖的功能,須要開闢一個線程共享的結構,若是您使用windows或者linux提供的pthread庫,libevent已經定義好了。

#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

libevent針對win32平臺定義了evthread_use_windows_threads,

libevent針對Linux thread庫 定義了evthread_use_pthreads

evthread_use_pthread函數是這樣的

int
evthread_use_pthreads(void)
{
    //pthread lock callback結構體對象
    struct evthread_lock_callbacks cbs = {
        //鎖的版本
        EVTHREAD_LOCK_API_VERSION,
        //鎖的屬性
        EVTHREAD_LOCKTYPE_RECURSIVE,
        //建立鎖
        evthread_posix_lock_alloc,
        //回收鎖
        evthread_posix_lock_free,
        //加鎖回調函數
        evthread_posix_lock,
        //解鎖回調函數
        evthread_posix_unlock
    };
    //條件變量回調結構體對象
    struct evthread_condition_callbacks cond_cbs = {
        //條件變量的版本
        EVTHREAD_CONDITION_API_VERSION,
        //建立條件變量
        evthread_posix_cond_alloc,
        //回收條件變量
        evthread_posix_cond_free,
        //激活條件的回調函數
        evthread_posix_cond_signal,
        //條件不知足阻塞的回調函數
        evthread_posix_cond_wait
    };

    //設置互斥鎖的屬性
    /* Set ourselves up to get recursive locks. */
    if (pthread_mutexattr_init(&attr_recursive))
        return -1;
    if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
        return -1;
    //將cbs的屬性設置到全局變量中,分爲調試和正常模式
    evthread_set_lock_callbacks(&cbs);
    //一樣將cond_cbs設置到全局變量
    evthread_set_condition_callbacks(&cond_cbs);
    //設置線程id到全局變量
    evthread_set_id_callback(evthread_posix_get_id);
    return 0;
}

這幾個結構體以下

#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 *);

The evthread_lock_callbacks structure describes your locking callbacks and their abilities. For the version described above, the lock_api_version field must be set to

EVTHREAD_LOCK_API_VERSION. The supported_locktypes field must be set to a bitmask of the EVTHREAD_LOCKTYPE_* constants to describe which lock types you can support.

(As of 2.0.4-alpha, EVTHREAD_LOCK_RECURSIVE

is mandatory and EVTHREAD_LOCK_READWRITE is unused.) The alloc function must return a new lock of the specified type. The free function must release all resources held by a lock of the

specified type. The lock function must try to acquire the lock in the specified mode, returning 0 on success and nonzero on failure. The unlock function must try to unlock the lock, returning 0 on success and nonzero on failure.

理解:

evthread_lock_callbacks 包括了鎖的回調函數和他們的功能,lock_api_version 要被設置爲EVTHREAD_LOCK_API_VERSION,

supported_locktypes 應該設置爲本身須要的EVTHREAD_LOCKTYPE_開頭的幾個類型的bitmask按位或

alloc 函數返回指定類型的鎖,free 函數釋放指定類型的鎖的全部資源,lock 函數試圖獲取制定模式的鎖,成功返回0,失敗返回非0.

unlock 解鎖函數釋放指定的鎖,成功返回0,失敗返回非0

 

Recognized lock types are:

0

A regular, not-necessarily recursive lock.

EVTHREAD_LOCKTYPE_RECURSIVE

A lock that does not block a thread already holding it from requiring it again. Other threads can acquire the lock once the thread holding it has unlocked it as many times

as it was initially locked.

EVTHREAD_LOCKTYPE_READWRITE

A lock that allows multiple threads to hold it at once for reading, but only one thread at a time to hold it for writing. A writer excludes all readers.

 

0表示常規鎖,不能夠被重複上鎖

 

EVTHREAD_LOCKTYPE_RECURSIVE:這種鎖當一個線程持有,該線程能夠繼續獲取他而不被阻塞,其餘線程須要等到該線程釋放這個鎖後能夠獲取到這個鎖,

而且能夠屢次加鎖。

 

EVTHREAD_LOCKTYPE_READWRITE:這種鎖多線程能夠在讀的時候都獲取到他,可是寫操做時只容許一個線程持有。

 

Recognized lock modes are:

EVTHREAD_READ

For READWRITE locks only: acquire or release the lock for reading.

EVTHREAD_WRITE

For READWRITE locks only: acquire or release the lock for writing.

EVTHREAD_TRY

For locking only: acquire the lock only if the lock can be acquired immediately.

EVTHREAD_READ和EVTHREAD_WRITE都是針對READWRITE 鎖的獲取和釋放。

EVTHREAD_TRY:這個模式只在能當即得到鎖的時候獲取鎖,不然不等待。

 

The id_fn argument must be a function returning an unsigned long identifying what thread is calling the function. It must always return the same number for the same thread, and must not ever return the same number for two different threads if they are both executing at the same time.

id_fn函數返回一個unsigned long標識調用該函數的線程。不一樣線程的返回值不一樣,同一個線程的返回值相同。

The evthread_condition_callbacks structure describes callbacks related to condition variables. For the version described above, the lock_api_version field must be set to EVTHREAD_CONDITION_API_VERSION. The alloc_condition function must return a pointer to a new condition variable. It receives 0 as its argument. The free_condition function must release storage and resources held by a condition variable. The wait_condition function takes three arguments: a condition allocated by alloc_condition, a lock allocated by the evthread_lock_callbacks.alloc function you provided, and an optional timeout. The lock will be held whenever the function is called; the function must release the lock, and wait until the condition becomes signalled or until the (optional) timeout has elapsed. The wait_condition function should return -1 on an error, 0 if the condition is signalled, and 1 on a timeout. Before it returns, it should make sure it holds the lock again. Finally, the signal_condition function should cause one thread waiting on the condition to wake up (if its broadcast argument is false) and all threads currently waiting on the condition to wake up (if its broadcast argument is true). It will only be held while holding the lock associated with the condition.

evthread_condition_callbacks 描述了幾個跟條件變量相關的回調函數。lock_api_version 應該被設置爲EVTHREAD_CONDITION_API_VERSION,alloc_condition 喊回一個指向新的環境變量的指針,

free_condition 釋放條件變量的資源,wait_condition 帶有三個參數,分別是alloc_condition開闢的條件變量,evthread_lock_callbacks開闢的鎖,以及一個可選的超時值,在調用這個函數時lock要提早加鎖,

以後,函數內部必須釋放鎖,等待條件被喚醒或者超時,wait_condition 在錯誤時返回-1,超時返回1,被激活返回0.在該函數內部返回以前,他要本身上鎖。signal_condition 激活單個線程,broadcast 參數設爲true時

全部等待該條件的線程被激活。只有持有和條件相關的鎖的時候線程纔會被掛起。

 

libevent中開闢鎖和釋放等等的回調函數以及條件變量的相關函數實現比較簡單,就不展開了,能夠查看evthread_pthread.c文件。

下面看下系統是如何調用

evthread_set_condition_callbacks()和evthread_set_lock_callbacks()分別將條件回調的結構體對象和鎖相關功能的結構體對象

賦值給全局變量

 

_evthread_cond_fns和_evthread_lock_fns,

libevent封裝了幾個經過_evthread_cond_fns和 _evthread_lock_fns 調用鎖和條件變量的接口,

都在evthread-internal.h文件裏。

EVTHREAD_ALLOC_LOCK(lockvar, locktype);

EVTHREAD_FREE_LOCK(lockvar, locktype);

EVLOCK_LOCK(lockvar,mode);

EVLOCK_UNLOCK(lockvar,mode);

EVTHREAD_ALLOC_COND(condvar);

EVTHREAD_FREE_COND(cond);

EVTHREAD_COND_SIGNAL(cond);

EVTHREAD_COND_WAIT(cond, lock);

等等,就不展開了,讀者本身閱讀。

 

個人公衆號

相關文章
相關標籤/搜索