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


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

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

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.

Libevent structures can generally work three ways with multithreading.

  • 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.

 

當你編寫多線程程序的時候,多個線程訪問同一塊數據並不安全。對於多線程libevent通常采取以下三種方式工作,

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

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

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

等等,就不展開了,讀者自己閱讀。

 

我的公眾號

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM