深入分析Memcached的线程 main()函数

本文介绍了一个基于Libevent的多线程程序设计,包括主线程如何初始化事件API并监听新连接,以及如何通过轮询方式分配新连接到WorkerThread进行处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三,在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);                    //开始监听主线程的注册事件
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值