深入分析Memcached的线程接入模型---中

三,main()函数中,初始化main_threadevent_base实例,见memcached.c

//定义main_thread的event_base实例 static struct event_base *main_base; //下面代码略 … /* initialize main thread libevent instance , 初始化事件API */ main_base = event_init(); //下面代码略 … /* 建立监听socket,并且注册libevent网络事件,server_socket通过调用下面介绍的dispatch_conn_new函数接收到的连接进行分发给worker_thread处理 */ errno = 0; if (settings.port && server_socket(settings.port, tcp_transport, portnumber_file)) { vperror("failed to listen on TCP port %d", settings.port); exit(EX_OSERR); } //下面代码略 … //主线程进入事件循环,监听socket是否有新连接到来 /* enter the event loop */ event_base_loop(main_base, 0);

 

 

四,main函数中,初始化各个worker 线程。

/* start up worker threads if MT mode */ thread_init(settings.num_threads, main_base); 该函数根据配置的线程数目settings.num_threads和之前建立的event_base main_base进行初始化,展开如下: /* * Initializes the thread subsystem, creating various worker threads. * nthreads Number of worker event handler threads to spawn * main_base Event base for main thread */ void thread_init(int nthreads, struct event_base *main_base) { int i; //初始化各种锁 pthread_mutex_init(&cache_lock, NULL); pthread_mutex_init(&stats_lock, NULL); pthread_mutex_init(&init_lock, NULL); pthread_cond_init(&init_cond, NULL); pthread_mutex_init(&cqi_freelist_lock, NULL); //初始化CQ_ITEM的预分配列表,为了提高分配CQ_ITEM的性能和防止 //过多的内存碎片,memcached会预先分配一批CQ_ITEM,需要直接从该列表中//直接获取一个 cqi_freelist = NULL; //通过堆分配nthreads个线程的LIBEVENT_THREAD的结构数组 //calloc跟malloc的不同点是会进行初始化 threads = calloc(nthreads, sizeof(LIBEVENT_THREAD)); if (! threads) { perror("Can't allocate thread descriptors"); exit(1); } //也就是main_thread, 负责分发 dispatcher_thread.base = main_base; dispatcher_thread.thread_id = pthread_self(); //对每个worker thread 建立通知管道,用于周知该worker_thread的CQ队列是否已经有可以处理的CQ_ITEM for (i = 0; i < nthreads; i++) { int fds[2]; if (pipe(fds)) { perror("Can't create notify pipe"); exit(1); } threads[i].notify_receive_fd = fds[0]; threads[i].notify_send_fd = fds[1]; //进一步初始化worker_thread的其他成员,详情见下面分析 setup_thread(&threads[i]); } /* Create threads after we've done all the libevent setup. */ for (i = 0; i < nthreads; i++) { //真正创建thread并且把thread_id赋值给对应的线程结构体 create_worker(worker_libevent, &threads[i]); } /* Wait for all the threads to set themselves up before returning. */ pthread_mutex_lock(&init_lock); while (init_count < nthreads) { pthread_cond_wait(&init_cond, &init_lock); } pthread_mutex_unlock(&init_lock); }

五,setup_thread函数的分析

/* * Set up a thread's information. * 参数 me 就是封装worker_thread的结构体的指针 */ static void setup_thread(LIBEVENT_THREAD *me) { //每个worker thread 都有自己的event_base实例,用于处理该worker_thread的网络读写事件 me->base = event_init(); if (! me->base) { fprintf(stderr, "Can't allocate event base/n"); exit(1); } /* Listen for notifications from other threads */ /*libevent API: 当notify_receive_fd 可读或者presist,则触发事件notify_event, 并且进入事件处理程序thread_libevent_process(重要函数) thread 结构体是通过heap 分配的,结构体里面的事件 notify_event也必须是heap分配 */ event_set(&me->notify_event, me->notify_receive_fd, EV_READ | EV_PERSIST, thread_libevent_process, me); //把事件notify_event安装到event_base event_base_set(me->base, &me->notify_event); /* int event_add(struct event *ev, struct timeval *tv); 将事件ev添加入事件系统,等待超时为tv,如果没有时间限制,则设为NULL 成功返回0,否则返回-1且出错原因设置到erron */ if (event_add(&me->notify_event, 0) == -1) { fprintf(stderr, "Can't monitor libevent notify pipe/n"); exit(1); } //每个worker thread都有属于自己的一个连接队列 me->new_conn_queue = malloc(sizeof(struct conn_queue)); if (me->new_conn_queue == NULL) { perror("Failed to allocate memory for connection queue"); exit(EXIT_FAILURE); } //初始化连接队列 cq_init(me->new_conn_queue); if (pthread_mutex_init(&me->stats.mutex, NULL) != 0) { perror("Failed to initialize mutex"); exit(EXIT_FAILURE); } me->suffix_cache = cache_create("suffix", SUFFIX_SIZE, sizeof(char*), NULL, NULL); if (me->suffix_cache == NULL) { fprintf(stderr, "Failed to create suffix cache/n"); exit(EXIT_FAILURE); } }

六,Create_worker函数的分析。

/* * Creates a worker thread. 真正创建线程的函数,第一个函数是线程执行的函数体,这里就是worker_libevent函数 arg 是LIBEVENT_THREAD结构体 */ static void create_worker(void *(*func)(void *), void *arg) { pthread_t thread; pthread_attr_t attr; int ret; pthread_attr_init(&attr); if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) { fprintf(stderr, "Can't create thread: %s/n", strerror(ret)); exit(1); } }

七,thread_libevent_process函数的分析。

thread_libevent_process函数是当worker_threadnotify_receive_fd可读时候,触发该函数的执行,该函数的处理逻辑就是从自己的CQ里面取下一个CQ_ITEM进行处理。

 

 

你可能感兴趣的:(thread,socket,struct,memcached,null,notifications)