【原创】libevent2中锁相关代码

在 bufferevent-internal.h 中 
bufferevent的锁操作函数 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

/** Internal: Given a bufferevent, return its corresponding bufferevent_private. */

// 内部使用宏

// 通过 bufferevent 结构获取其所属的 bufferevent_private 结构

#define BEV_UPCAST(b) EVUTIL_UPCAST((b), struct bufferevent_private, bev)

 

#ifdef _EVENT_DISABLE_THREAD_SUPPORT

    #define BEV_LOCK(b) _EVUTIL_NIL_STMT

    #define BEV_UNLOCK(b) _EVUTIL_NIL_STMT

#else

/** Internal: Grab the lock (if any) on a bufferevent */

// 内部使用宏

// 对 bufferevent 上锁

#define BEV_LOCK(b) do {    \

    struct bufferevent_private *locking =  BEV_UPCAST(b);   \

    EVLOCK_LOCK(locking->lock, 0);   \

} while (0)

 

/** Internal: Release the lock (if any) on a bufferevent */

// 内部使用宏

// 对 bufferevent 解锁

#define BEV_UNLOCK(b) do {  \

    struct bufferevent_private *locking =  BEV_UPCAST(b);   \

    EVLOCK_UNLOCK(locking->lock, 0); \

} while (0)

 

#endif

在 bufferevent.c 中 
bufferevent的锁使能 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

// 为 bufferevent_private 创建 bufferevent 并初始化内部各结构

int

bufferevent_init_common(struct bufferevent_private *bufev_private,

    struct event_base *base, const struct bufferevent_ops *ops, enum bufferevent_options options)

{

...

#ifndef _EVENT_DISABLE_THREAD_SUPPORT   // 如果编译时使能了线程支持

    if (options & BEV_OPT_THREADSAFE) { // 并且 bufferevent 也使能了线程支持

        if (bufferevent_enable_locking(bufev, NULL) < 0) {

            /* cleanup */

            evbuffer_free(bufev->input);

            evbuffer_free(bufev->output);

            bufev->input = NULL;

            bufev->output = NULL;

            return -1;

        }

    }

#endif

...

}

【bufferevent的锁设置】 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

// 为与 bufferevent 相关的各结构设置 lock

// NOTE: 所有结构都共用 lock

int

bufferevent_enable_locking(struct bufferevent *bufev, void *lock)

{

#ifdef _EVENT_DISABLE_THREAD_SUPPORT

    return -1;

#else

    struct bufferevent *underlying;

 

    // 首先要确保 bufev 所属的 bufferevent_private 中没有 lock

    if (BEV_UPCAST(bufev)->lock)

        return -1;

    // 若为 socket 或 pair 类型的 bufferevent 则返回 NULL

    underlying = bufferevent_get_underlying(bufev);

 

    // 若外部未提供 lock ,但 bufev 含有底层 bufferevent

    // 并且该底层 bufferevent 所属 bufferevent_private 中存在 lock 变量

    // 则直接使用该 lock 做为 bufferevent 的锁

    if (!lock && underlying && BEV_UPCAST(underlying)->lock) {

        lock = BEV_UPCAST(underlying)->lock;

        BEV_UPCAST(bufev)->lock = lock;

        BEV_UPCAST(bufev)->own_lock = 0;

    } else if (!lock) { // 外部未提供 lock 且底层也无可用锁

        // 则自行分配 lock 做为 bufferevent 的锁

        EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);

        if (!lock)

            return -1;

        BEV_UPCAST(bufev)->lock = lock;

        BEV_UPCAST(bufev)->own_lock = 1;

    } else {    // 外部提供 lock 供直接使用

        BEV_UPCAST(bufev)->lock = lock;

        BEV_UPCAST(bufev)->own_lock = 0;

    }

    // 为 input 和 output 缓冲区设置锁

    evbuffer_enable_locking(bufev->input, lock);

    evbuffer_enable_locking(bufev->output, lock);

 

    if (underlying && !BEV_UPCAST(underlying)->lock)

        bufferevent_enable_locking(underlying, lock);

 

    return 0;

#endif

}

在 buffer.c 中 
【evbuffer的锁设置】 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// 为 evbuffer 设置 lock

int

evbuffer_enable_locking(struct evbuffer *buf, void *lock)

{

#ifdef _EVENT_DISABLE_THREAD_SUPPORT

    return -1;

#else

    // 若 evbuffer 内部已存在 lock 则直接返回

    if (buf->lock)

        return -1;

 

    if (!lock) {

        EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);

        if (!lock)

            return -1;

        buf->lock = lock;

        buf->own_lock = 1;

    } else {

        buf->lock = lock;

        buf->own_lock = 0;

    }

 

    return 0;

 

#endif

}

在 evbuffer-internal.h 中 
【evbuffer中的锁定义】 

?


1

2

3

4

5

6

7

8

struct evbuffer {

...

#ifndef _EVENT_DISABLE_THREAD_SUPPORT

/** A lock used to mediate access to this buffer. */

    void *lock;

#endif

...

}

在 event-internal.h 中 
【event_base的锁定义】 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

struct event_base {

...

#ifndef _EVENT_DISABLE_THREAD_SUPPORT

    /* threading support */

    /** The thread currently running the event_loop for this base */

    unsigned long th_owner_id;

    /** A lock to prevent conflicting accesses to this event_base */

    // 用于防止针对当前 event_base 冲突性访问的锁

    void *th_base_lock;

    /** The event whose callback is executing right now */

    struct event *current_event;

    /** A condition that gets signalled when we're done processing an

     * event with waiters on it. */

    void *current_event_cond;

    /** Number of threads blocking on current_event_cond. */

    int current_event_waiters;

#endif

...

};

在 event.c 中 
【event_base的锁使能】 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

struct event_base *

event_base_new_with_config(const struct event_config *cfg)

{

...

#ifndef _EVENT_DISABLE_THREAD_SUPPORT  // 如果支持多线程锁

    if (EVTHREAD_LOCKING_ENABLED() &&  // 测试是否锁函数为 NULL ,即 libevent 是否初始化为支持多线程

        (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) { // 判定当前配置是否支持锁

        int r;

        // 申请递归锁

        EVTHREAD_ALLOC_LOCK(base->th_base_lock, EVTHREAD_LOCKTYPE_RECURSIVE);

        base->defer_queue.lock = base->th_base_lock;

        // 申请条件变量

        EVTHREAD_ALLOC_COND(base->current_event_cond);

        r = evthread_make_base_notifiable(base);

        if (r<0) {

            event_warnx("%s: Unable to make base notifiable.", __func__);

            event_base_free(base);

            return NULL;

        }

    }

#endif

...

}

在 evthread-internal.h 中 
【平台和多线程相关锁定义】 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#ifndef WIN32  // 非 Windows 平台

/* On Windows, the way we currently make DLLs, it's not allowed for us to

 * have shared global structures.  Thus, we only do the direct-call-to-function

 * code path if we know that the local shared library system supports it.

 */

#define EVTHREAD_EXPOSE_STRUCTS

#endif

 

 

#if ! defined(_EVENT_DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS) // 多线程支持+非WIN平台

...

#elif ! defined(_EVENT_DISABLE_THREAD_SUPPORT)  // 多线程支持+WIN平台

...

#else /* _EVENT_DISABLE_THREAD_SUPPORT */  // 不支持多线程

...

#endif

【event_base锁函数】 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

#if ! defined(_EVENT_DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS) // 多线程支持+非WIN平台

...

/** Acquire a lock. */

// 获取锁

#define EVLOCK_LOCK(lockvar,mode)   \

do {    \

    if (lockvar)    \

    _evthread_lock_fns.lock(mode, lockvar); \

} while (0)

 

 

/** Release a lock */

#define EVLOCK_UNLOCK(lockvar,mode) \

do {    \

    if (lockvar)    \

    _evthread_lock_fns.unlock(mode, lockvar);   \

} while (0)

...

/** Lock an event_base, if it is set up for locking.  Acquires the lock

    in the base structure whose field is named 'lockvar'. */

// 锁定 event_base ,如果该 event_base 确实支持锁

// 获取 base 结构中的锁,锁名由 lockvar 指定

#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \

    EVLOCK_LOCK((base)->lockvar, 0); \

} while (0)

 

 

/** Unlock an event_base, if it is set up for locking. */

#define EVBASE_RELEASE_LOCK(base, lockvar) do { \

    EVLOCK_UNLOCK((base)->lockvar, 0);   \

} while (0)

...

#elif ! defined(_EVENT_DISABLE_THREAD_SUPPORT)  // 多线程支持+WIN平台

...

在 thread.h 中

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

#if !defined(_EVENT_DISABLE_THREAD_SUPPORT) || defined(_EVENT_IN_DOXYGEN)

 

#define EVTHREAD_LOCK_API_VERSION 1

 

/**

   @name Types of locks

         锁类型

 

   其实这里包含第三种锁类型,即 0 值代表 普通锁

 

   @{*/

/** A recursive lock is one that can be acquired multiple times at once by the

 * same thread.  No other process can allocate the lock until the thread that

 * has been holding it has unlocked it as many times as it locked it. */

// 递归锁类型是指,该锁可以在同一个线程中被获取多次;其他线程无法分配该锁,直到

// 持有该锁的线程对其解锁相同数量的次数

#define EVTHREAD_LOCKTYPE_RECURSIVE 1

/* A read-write lock is one that allows multiple simultaneous readers, but

 * where any one writer excludes all other writers and readers. */

#define EVTHREAD_LOCKTYPE_READWRITE 2

/**@}*/

 

/** This structure describes the interface a threading library uses for

 * locking.   It's used to tell evthread_set_lock_callbacks() how to use

 * locking on this platform.

 */

// 线程锁操作函数指针结构体

// 该结构用于告知 evthread_set_lock_callbacks() 在当前平台上如何使用锁

struct evthread_lock_callbacks {

    /** The current version of the locking API.  Set this to

    * EVTHREAD_LOCK_API_VERSION */

    int lock_api_version;

    /** Which kinds of locks does this version of the locking API

    * support?  A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and

    * EVTHREAD_LOCKTYPE_READWRITE.

    *

    * (Note that RECURSIVE locks are currently mandatory, and

    * READWRITE locks are not currently used.)

    **/

    unsigned supported_locktypes;

    /** Function to allocate and initialize new lock of type 'locktype'.

    * Returns NULL on failure. */

    void *(*alloc)(unsigned locktype);

    /** Function to release all storage held in 'lock', which was created

    * with type 'locktype'. */

    void (*free)(void *lock, unsigned locktype);

    /** Acquire an already-allocated lock at 'lock' with mode 'mode'.

    * Returns 0 on success, and nonzero on failure. */

    // 以 'mode' 模式持有由 'lock' 指向的已经分配的锁;0 为获取成功,非零为失败

    int (*lock)(unsigned mode, void *lock);

    /** Release a lock at 'lock' using mode 'mode'.  Returns 0 on success,

    * and nonzero on failure. */

    int (*unlock)(unsigned mode, void *lock);

};

 

/** Sets a group of functions that Libevent should use for locking.

 * For full information on the required callback API, see the

 * documentation for the individual members of evthread_lock_callbacks.

 *

 * Note that if you're using Windows or the Pthreads threading library, you

 * probably shouldn't call this function; instead, use

 * evthread_use_windows_threads() or evthread_use_posix_threads() if you can.

 */

int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);

 

...

 

#if (defined(WIN32) && !defined(_EVENT_DISABLE_THREAD_SUPPORT)) || defined(_EVENT_IN_DOXYGEN)

/** Sets up Libevent for use with Windows builtin locking and thread ID

    functions.  Unavailable if Libevent is not built for Windows.

 

    @return 0 on success, -1 on failure. */

int evthread_use_windows_threads(void);           // windows 上的锁使能

/**

   Defined if Libevent was built with support for evthread_use_windows_threads()

*/

#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1

 

#endif

 

#if defined(_EVENT_HAVE_PTHREADS) || defined(_EVENT_IN_DOXYGEN)

/** Sets up Libevent for use with Pthreads locking and thread ID functions.

    Unavailable if Libevent is not build for use with pthreads.  Requires

    libraries to link against Libevent_pthreads as well as Libevent.

    令 libevent 可以使用 pthread 锁和相应的获取线程 id 的函数

    如果构建 libevent 时候不支持 pthread 则无法使用该函数

    使用时要求链接 libevent_pthreads 库和 libevent 库

 

    @return 0 on success, -1 on failure. */

int evthread_use_pthreads(void);               // linux 上的锁使能

/** Defined if Libevent was built with support for evthread_use_pthreads() */

#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1

 

#endif

 

/** Enable debugging wrappers around the current lock callbacks.  If Libevent

 * makes one of several common locking errors, exit with an assertion failure.

 *

 * If you're going to call this function, you must do so before any locks are

 * allocated.

 **/

void evthread_enable_lock_debuging(void);

 

#endif /* _EVENT_DISABLE_THREAD_SUPPORT */

在 whatsnew-2.0.txt 中 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

2.8. evthread_* functions for thread-safe structures.

 

  Libevent structures can now be built with locking support.  This code

  makes it safe to add, remove, and activate events on an event base from a

  different thread.  (Previously, if you wanted to write multithreaded code

  with Libevent, you could only an event_base or its events in one thread at

  a time.)

 

  If you want threading support and you're using pthreads, you can just

  call evthread_use_pthreads().  (You'll need to link against the

  libevent_pthreads library in addition to libevent_core.  These functions are

  not in libevent_core.)

 

  If you want threading support and you're using Windows, you can just

  call evthread_use_windows_threads().

 

  If you are using some locking system besides Windows and pthreads, You

  can enable this on a per-event-base level by writing functions to

  implement mutexes, conditions, and thread IDs, and passing them to

  evthread_set_lock_callbacks and related functions in event2/thread.h.

 

  Once locking functions are enabled, every new event_base is created with a

  lock.  You can prevent a single event_base from being built with a lock

  disabled by using the EVENT_BASE_FLAG_NOLOCK flag in its

  event_config.  If an event_base is created with a lock, it is safe to call

  event_del, event_add, and event_active on its events from any thread.  The

  event callbacks themselves are still all executed from the thread running

  the event loop.

 

  To make an evbuffer or a bufferevent object threadsafe, call its

  *_enable_locking() function.

 

  The HTTP api is not currently threadsafe.

 

  To build Libevent with threading support disabled, pass

  --disable-thread-support to the configure script.

时间: 2024-09-13 04:25:24

【原创】libevent2中锁相关代码的相关文章

理解oracle锁和闩(1)与锁相关的数据结构

在oracle眼里,锁不是稀有资源,相反地,只要需要,你就应该长期地持有对数据所加的锁.行级锁根本没有相关开销,对1千万行锁定所需的资源数与对1行锁定所需的资源数完全相同,这是个常量. 在SGA中和锁相关的内存有两块:队列资源池和锁池.池:指的就是一块固定大小的内存. 队列资源池:存放所有的队列资源.锁就是队列资源. 例如:一个表上的TM锁就是一个队列资源,有多少个表就有多少个TM队列资源,如果有一个表的TM锁被持有,他就会被放进队列资源池.为了对他们加以区分,要为各个表的TM队列资源起个名字,

biginteger-Java中n!的代码看不懂啊,求解释

问题描述 Java中n!的代码看不懂啊,求解释 import java.math.BigInteger; import java.util.*; public class Main{ protected static ArrayList table = new ArrayList(); static { table.add(BigInteger.valueOf(1)); } public static synchronized BigInteger factorial(int x) { for

jsp-JSP中编写JS代码过程中,调用了一个JSP表达式,发现一个问题,麻烦各位大神解答

问题描述 JSP中编写JS代码过程中,调用了一个JSP表达式,发现一个问题,麻烦各位大神解答 背景: 楼主使用Myelipse新建了一个Web项目,在编写一个JSP文件的时候遇到一个问题,首先是使用了img,并且写了一个事件,代码如下: <imgclass="poke" src="poke/back.jpg" title="hit" id="play_id_3" onClick="change_pic()&qu

link中编译的代码,怎么确定使用的变量是不是增加列?

问题描述 link中编译的代码,怎么确定使用的变量是不是增加列? link中编译的代码,怎么确定使用的变量是不是增加列? 解决方案 反射遍历Attribute 找有[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]的字段

javascript-js中的java代码如何访问js中方法的参数??见图

问题描述 js中的java代码如何访问js中方法的参数??见图 如何让1处的值传到2处这里?? 解决方案 需要用ajax提交你的index到服务器,服务器端无法直接获取客户端js的变量值 <script src=""http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.4.1.min.js""></script><script type=""text/javascript&qu

干掉你程序中的僵尸代码

随着万圣节越来越流行,我感觉有必要跟大家讨论一下一个在软件开发中非常普遍的问题:僵尸代码.几乎所有我接触过的代码库里都四散着很多小段的,甚至大片大片的被注释掉的代码.这就是僵尸代码. //目前禁用这项功能.Jimmy在写这段代码时肯定是喝醉了. //你可能以为这里发生了恐怖的代码凶手案-不,不,我只是把它们注释掉了- 为什么称它们为僵尸代码?你知道,僵尸不并不是真的死的.就像恐怕电影里告诉我们的,尽管僵尸看起来是死人,但它们仍有能力四处出没袭击我们.相同的道理,僵尸代码也是处于不生不死之间-它们

mfc-求大神解答,在MFC中如何通过代码将本地的图片加载到资源中并分配ID?

问题描述 求大神解答,在MFC中如何通过代码将本地的图片加载到资源中并分配ID? 求大神解答,在MFC中如何通过代码将本地的图片加载到资源中并分配ID? 解决方案 资源是编译时候的概念,加载是运行时候的概念. 资源被资源编译器编译,再通过链接器附加到可执行文件上.程序运行的时候它是只读的. 解决方案二: 不知道你为什么要怎么做,不可以直接在程序中调用资源吗 解决方案三: 用CXImage等类库可以加载文件 解决方案四: 用CImage加载本地图片就不要放到资源视图中了,也就没有资源ID的概念了.

Dreamweaver CS5 中启用 WordPress 代码提示功能的图文方法

使用 Dreamweaver 这样的可视化的 IDE 工具进行编程的最大的一个好处是它的代码提示功能,只要输入几个字符,IDE 工具就会智能的给出一系列可选的函数或者变量让你输入. 代码提示功能的好处是非常明显的,比如你对某个函数记不清楚,就可以通过代码提示功能快速输入,而不用去搜索和查资料,即使非常清楚,也可以通过代码提示功能快速输入而无需输入每个字符,这样的对编程效率提高是非常明显的. Dreamweaver CS5 支持 WordPress 代码提示 我们知道 Dreamweaver 代码

VBScript基础教程之二在HTML页面中添加VBscript代码

vbscript|基础教程|页面 SCRIPT 元素用于将 VBScript 代码添加到 HTML 页面中. <SCRIPT> 标记 VBScript 代码写在成对的 <SCRIPT> 标记之间.例如,以下代码为一个测试传递日期的过程: <SCRIPT LANGUAGE="VBScript"> <!-- Function CanDeliver(Dt) CanDeliver = (CDate(Dt) - Now()) > 2 End Fun