三,在main()函数中,初始化main_thread的event_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);
1 main.cpp
初始化WorkerThread(实际上每个WorkerThread负责一个外部连接),启动主线程server connect事件监听(这里我不用socket通信,直接监听命令行),一旦命令行有命令输入,就会激发事件,然后主线程就会以轮询的方式从空闲线程中选出一条来进行后续操作,并通过pipe通知该workerThread有新item可以处理。
main.cpp
#include<unistd.h> //getopt
#include<stdlib.h> //atoi
#include<event.h> //libevent
#include<stdio.h>
#include<pthread.h>
#include<string.h> //strerror
#include<errno.h>
#include<fcntl.h> //open
#include"WorkerThreads.h"
//Globally Settings
struct Settings
{
int num_threads;
};
struct Settings settings;
//Globally Values
static struct event_base *main_base;
//main thread dispatch event_base
static int last_thread=-1;
#define DATA_BUFFER_SIZE 2048
WorkerThreads *workerThreads;
//Globally Functions
void readCommand(Settings settings){}
void thread_init(int nthreads) //void thread_init(int nthreads,struct
event_base *main_base)
{
workerThreads=new WorkerThreads(nthreads);
workerThreads->initiate();
}
void dispatch_conn_new(int sfd,int wrfd)
{
CQ_ITEM *item=cqi_new();
int tid=(last_thread+1)%settings.num_threads; //轮询选出workerThread(数组)
LIBEVENT_THREAD *thread=workerThreads->threads+tid;
last_thread=tid;
item->sfd=sfd;
//封装必要的信息到item结构,后面会利用item封装为conn
item->init_state=conn_read;
item->event_flags=EV_READ | EV_PERSIST;
// item->read_buffer_size=DATA_BUFFER_SIZE;
item->read_buffer_size=wrfd;
item->transport=tcp_transport;
cq_push(thread->new_conn_queue,item); //item需要插入到被选中的thread的全局queue里面
printf("item fd is:%d\n",item->sfd);
int wc=write(thread->notify_send_fd,"",1);
//主线程和workerThread的通信方式,写入到notify_send_fd告诉辅助线程item准备好了,可以处理
}
void base_event_handler(const int fd, const short which,void* arg)
{
char buf[128];
int rc=read(fd,buf,sizeof(buf));
buf[rc]='\0';
printf("%s\n",buf);
//int testfd=open("./testfile.txt",O_RDWR);
int pipefds[2];
pipe(pipefds);
dispatch_conn_new(pipefds[0],pipefds[1]);
//这里使用pipe来模拟memcached中外部连接后带来的通信fd,注意要想在libevent上监听fd,则不能使用regular file的fd,libevent不支持
}
int main(int argc, char **argv)
{
// readCommand(settings); //set threads counts
int c;
while(-1!=(c=getopt(argc,argv,"t:"))) //从命令行读取workerThread数
{
switch (c)
{
case 't':
settings.num_threads=atoi(optarg);
break;
}
}
main_base=event_init();
//主线程的监听外部连接(这里监听标准输入),memcached则借助自定义的协议,接收来自Unix域/tcp/udp的客户端请求。
struct event inputEvent;
event_set(&inputEvent,STDIN_FILENO,EV_READ | EV_PERSIST,base_event_handler,NULL); //一旦有事件触发,则委托给base_event_handler处理
event_base_set(main_base,&inputEvent);
event_add(&inputEvent,0);
conn_init();
thread_init(settings.num_threads); //WorkerThread初始化,详细见workerThreads->initiate();
event_base_loop(main_base,0); //开始监听主线程的注册事件
}