连接队列
# Memcached源码阅读九 连接队列
Memcached
中Master线程和Worker线程之间通信连接信息时,是通过连接队列来通信的,即Master线程投递一个消息到Worker线程的连接队列中,Worker线程从连接队列中读取链接信息来执行连接操作,下面我们简单分析下Memcached的连接队列结构。
typedef struct conn_queue_item CQ_ITEM;//每个连接信息的封装
struct conn_queue_item {
int sfd;//accept之后的描述符
enum conn_states init_state;//连接的初始状态
int event_flags;//libevent标志
int read_buffer_size;//读取数据缓冲区大小
enum network_transport transport;//内部通信所用的协议
CQ_ITEM *next;//用于实现链表的指针
};
typedef struct conn_queue CQ;//连接队列的封装
struct conn_queue {
CQ_ITEM *head;//头指针,注意这里是单链表,不是双向链表
CQ_ITEM *tail;//尾部指针,
pthread_mutex_t lock;//锁
pthread_cond_t cond;//条件变量
};
//连接队列初始化
static void cq_init(CQ *cq) {
pthread_mutex_init(&cq->lock, NULL);//初始化锁
pthread_cond_init(&cq->cond, NULL);//初始化条件变量
cq->head = NULL;
cq->tail = NULL;
}
//获取一个连接
static CQ_ITEM *cq_pop(CQ *cq) {
CQ_ITEM *item;
pthread_mutex_lock(&cq->lock);//执行加锁操作
item = cq->head;
//获得头部指针指向的数据
if (NULL != item) {
//更新头指针信息
cq->head = item->next;
//这里为空的话,则尾指针也为空,链表此时为空
if (NULL == cq->head)
cq->tail = NULL;
}
//释放锁操作
pthread_mutex_unlock(&cq->lock);
return item;
}
//添加一个连接信息
static void cq_push(CQ *cq, CQ_ITEM *item) {
item->next = NULL;
pthread_mutex_lock(&cq->lock);//执行加锁操作
//如果链表目前是空的
if (NULL == cq->tail)
//则头指针指向该结点
cq->head = item;
else
cq->tail->next = item;//添加到尾部
cq->tail = item;
//尾部指针后移
pthread_cond_signal(&cq->cond);
//唤醒条件变量,如果有阻塞在该条件变量的线程,则会唤醒该线程
pthread_mutex_unlock(&cq->lock);
}
//创建连接队列
static CQ_ITEM *cqi_new(void) {
CQ_ITEM *item = NULL;
pthread_mutex_lock(&cqi_freelist_lock);
//加锁,保持数据同步
if (cqi_freelist) {
//更新空闲链表信息
item = cqi_freelist;
cqi_freelist = item->next;
}
pthread_mutex_unlock(&cqi_freelist_lock);
//如果空闲链表没有多余的链接
if (NULL == item) {
int i;
//初始化64个空闲连接信息
item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC);
if (NULL == item)
return NULL;
//将空闲的连接信息进行链接
for (i = 2; i < ITEMS_PER_ALLOC; i++)
item[i - 1].next = &item[i];
pthread_mutex_lock(&cqi_freelist_lock);
item[ITEMS_PER_ALLOC - 1].next = cqi_freelist;//加入到空闲链表中
cqi_freelist = &item[1];
pthread_mutex_unlock(&cqi_freelist_lock);
}
return item;
}
//释放item,也就是将item添加到空闲链表中
static void cqi_free(CQ_ITEM *item) {
pthread_mutex_lock(&cqi_freelist_lock);
item->next = cqi_freelist;
cqi_freelist = item;
pthread_mutex_unlock(&cqi_freelist_lock);
}
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
105
106
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
105
106
空闲链表类似于一种连接池的实现,服务器开发中经常需要各种池操作,大家在实现类似池时,可以做参考。
编辑 (opens new window)
上次更新: 2023/12/11, 22:32:09