Libevent源码解析
libevent源码深度剖析十三libevent信号处理注意点
libevent源码深度剖析十三libevent信号处理注意点系列目录(1)libevent源码深度剖析一序(2)libevent源码深度剖析二 Reactor模式(3)libevent源码深度剖析三 libevent基本使用场景和事件流程(4)libevent源码深度剖析四 libevent源代码文件组织(5)libevent源码深度剖析五 libevent的核心:事件event(6)libevent源码深度剖析六初见事件处理框架(7)libevent源码深度剖析七事件主循环(8)libevent源码深度剖析八集成信号处理(9)libevent源码深度剖析九集成定时器事件(10)libevent源码深度剖析十支持I/O多路复用技术(11)libevent源码深度剖析十一时间管理(12)libevent源码深度剖析十二让libevent支持多线程(13)libevent源码深度剖析十三 libevent信号处理注意点前面讲到了 libevent 实现多线程的方法,然而在多线程的环境中注册信号事件,还是有一些情况需要小心处理,那就是不能在多个 libevent 实例上注册信号事件。
依然冠名追加到 libevent 系列。
以 2 个线程为例,做简单的场景分析。
1 首先是创建并初始化线程 1 的 libevent 实例 base1 ,线程 1 的 libevent 实例 base2 ;2 在 base1 上注册 SIGALRM 信号;在 base2 上注册 SIGINT 信号;3 假设当前 base1 和 base2 上都没有注册其他的事件;4 线程 1 和 2 都进入 event_base_loop 事件循环:5 假设线程 1 先进入 event_base_loop ,并设置 evsignal_base = base1 ;并等待;6 接着线程 2 也进入 event_base_loop ,并设置 evsignal_base = base2 ;并等待;于是 evsignal_base 就指向了 base2 ;7 信号 ALARM 触发,调用服务例程:1static void evsignal_handler(int sig){2 ...3 evsignal_base->sig.evsigcaught[sig]++;4 evsignal_base->sig.evsignal_caught = 1;5 /* Wake up our notification mechanism */6 send(evsignal_base->sig.ev_signal_pair[0], 'a', 1, 0);7 ...8}于是 base2 得到通知 ALARM 信号发生了,而实际上 ALARM 是注册在 base1 上的, base2 上的 ALARM 注册 event 是空的,于是处理函数将不能得到调用;因此在 libevent 中,如果需要处理信号,只能将信号注册到一个 libevent 实例上。
libevent源码分析
libevent源码分析这两天没事,看了⼀下Memcached和libevent的源码,做个⼩总结。
1、⼊门1.1、概述Libevent是⼀个⽤于开发可扩展性⽹络服务器的基于事件驱动(event-driven)模型的⽹络库。
Libevent有⼏个显著的亮点:(1)事件驱动(event-driven),⾼性能;(2)轻量级,专注于⽹络,不如 ACE 那么臃肿庞⼤;(3)源代码相当精炼、易读;(4)跨平台,⽀持 Windows、Linux、*BSD和 Mac Os;(5)⽀持多种 I/O多路复⽤技术, epoll、poll、dev/poll、select 和kqueue 等;(6)⽀持 I/O,定时器和信号等事件;(7)注册事件优先级;Libevent 已经被⼴泛的应⽤,作为底层的⽹络库;⽐如 memcached、 Vomi t、 Nylon、 Netchat等等。
1.2、⼀个简单⽰例代码1int lasttime;23static void4 timeout_cb(int fd, short event, void *arg)5 {6struct timeval tv;7struct event *timeout = arg;8int newtime = time(NULL);910//printf("%s: called at %d: %d\n", __func__, newtime,11 printf("%s: called at %d: %d\n", "timeout_cb", newtime,12 newtime - lasttime);13 lasttime = newtime;1415 evutil_timerclear(&tv);16 _sec = 2;17//重新注册event18 event_add(timeout, &tv);19 }2021int22 main (int argc, char **argv)23 {24struct event timeout;25struct timeval tv;2627/* Initalize the event library */28//初始化event环境29 event_init();3031/* Initalize one event */32//设置事件33 evtimer_set(&timeout, timeout_cb, &timeout);3435 evutil_timerclear(&tv);36 _sec = 2;37//注册事件38 event_add(&timeout, &tv);3940 lasttime = time(NULL);4143 event_dispatch();4445return (0);46 }这是⼀个简单的基于libevent的定时器程序,运⾏结果:⽤libevent编程⾮常简单,只需要调⽤event_init初始化环境,然后调⽤event_add注册相应的事件,接着调⽤event_dispatch等待并处理相应的事件即可。
LibEvent代码阅读--多缓冲区和零拷贝技术
最近项目赶着发版本,连续好几天通宵赶工,瓶颈出现在了性能问题,各种方案验证和修订。
周末闲下来还是对之前学习的libevent进行总结。
在libevent的报文收发处理过程中采用了一系列提高收发性能的技术,其中多缓冲区的接收和发送以及零拷贝技术等,本篇主要分析这些技术在libevent中的运用。
首先简要的介绍一下两种技术:多缓存的收据发送和接收:点击(此处)折叠或打开1.struct iovec {2. ptr_t iov_base;/* Starting address */3. size_t iov_len;/* Length in bytes */4.};5.6.int readv(int fd,const struct iovec *vector,int count);7.int writev(int fd,const struct iovec *vector,int count);其中的iovec是指一个缓冲区,包含了数据区的地址和对应的长度,在两个函数中的count是指iovec的个数。
这种多缓冲区的发送和接收操作性能相对更好。
而iovec需要在使用前分配好相关的内存空间。
零拷贝技术:零拷贝能够减少数据之间无效的数据拷贝,而直接进行数据的发送,通常在数据发送的过程中使用,特别是在文件发送的过程中被经常使用。
通常情况下要将文件a.txt中的内容发送出去,需要进行如下的操作:读取文件内容: read(),然后发送读取的内容send()。
因此一个完整的过程会出现一个读取再发送的操作,往往文件的IO操作是相对费时的操作,因此零拷贝技术实际上就是较少了read()的处理过程,即在发送数据前不需要进行文件的读取操作,这样相对而言就会提高处理的性能。
关于零拷贝的技术有很多方式,这里主要介绍sendfile和mmap.其中的mmap是采用映射的方式将文件内容映射到内存中,在发送报文时直接读取内存中的内容,这样就能提高发送效率。
libevent evthread_use_pthreads -回复
libevent evthread_use_pthreads -回复libevent是一个开源的事件驱动网络库,它提供了一个高效的跨平台的事件驱动模型,用于构建可扩展的网络应用程序。
evthread_use_pthreads 是libevent库中的一个函数,它用于设置使用pthread线程库作为底层的多线程实现。
本文将深入探讨libevent库及其事件驱动模型以及evthread_use_pthreads函数的作用和用法。
一、libevent库和事件驱动模型简介libevent是一个轻量级、高性能、事件驱动的网络库,最初由Nick Mathewson于2000年开发,并在2002年发布。
它的设计目标是提供一个统一的、跨平台的接口,用于处理网络事件和I/O操作,以支持高并发的网络应用程序。
libevent库可以在多个操作系统上运行,包括Windows、Linux、BSD等。
libevent采用了事件驱动的编程模型,通过使用异步的、非阻塞的I/O操作和事件回调机制来处理网络事件。
在传统的阻塞式I/O模型中,每个连接都需要一个独立的线程或进程来处理,当同时有大量的连接时,会消耗大量的系统资源。
而在事件驱动模型中,通过一个主循环不断监听和分发事件,将连接的处理交给事件回调函数,可以大大提高系统的吞吐量和性能。
二、libevent库的特性和用途1. 高性能:libevent采用非阻塞I/O和事件回调机制,能够处理大量的并发连接,实现高性能的网络应用程序。
2. 跨平台:libevent可以在多个操作系统上运行,包括Windows、Linux、BSD、macOS等。
3. 支持多种网络协议:libevent支持多种常用的网络协议,如TCP、UDP、HTTP等,能够满足不同类型的网络应用需求。
4. 支持定时器:libevent提供了定时器功能,可以方便地实现定时任务的调度和执行。
5. 可扩展性:libevent的设计模式允许用户自定义事件源和事件处理器,以满足复杂应用的需求。
libevent源码分析event_base_dispatch,event_base_lo。。。
libevent源码分析event_base_dispatch,event_base_lo。
接⼝:event_base_dispatch/**Event dispatching loop 事件分配循环This loop will run the event base until either there are no more pending oractive, or until something calls event_base_loopbreak() orevent_base_loopexit().这个循环将会运⾏event base,知道没有等待的或者活动的事件,或者其它的调⽤了event_base_loopbreak()或event_base_loopexit().@param base the event_base structure returned by event_base_new() orevent_base_new_with_config() event_base_new() 或者 event_base_new_with_config() 返回的event_base对象@return 0 if successful, -1 if an error occurred, or 1 if we exited becauseno events were pending or active. 成功返回0,错误返回-1,或者1(当没有等待的或者活动事件时退出,会返回1)@see event_base_loop()*/EVENT2_EXPORT_SYMBOLint event_base_dispatch(struct event_base *base);intevent_base_dispatch(struct event_base *event_base){return (event_base_loop(event_base, 0));}跟踪event_base_loop接⼝/**Wait for events to become active, and run their callbacks.等待events 变成活动的,并运⾏对应的回调函数。
黑马程序员C语言教程:libevent
标题:深入浅出-服务器高并发库libevent (一)1安装libevent是一个开源的高并发服务器开发包,官方地址/ libevent目前有两个版本一个是1.4系列版本,一个是2.0系列版本。
我们可以在官方网站上看到类似有个stable表示稳定版本。
libevent-1.4.15-stable.tar.gz对于初学者学习,建议从1.4版本学起。
在安装libevent之前先判断本电脑是否已经安装了通过指令ls -al /usr/lib|grep libevent如果没有任何信息则表示没有安装,有的话如果发现libevent是1.3以下版本,则可以同过执行rpm -e libevent —nodeps 进行卸载。
如果是其他操作系统使用其他对应卸载指令即可。
对于下好的tar包,通过tar -zxvf libevent-release-1.4.15-stable.tar.gz指令解压。
然后执行./configure命令,但是有的包可能没有configure文件,却存在一个autogen.sh 脚本,运行这个脚本。
(如果运行不起来请安装autoconf包)然后./configure–prefix=/usrmakesudo make install安装完之后执行ls -al /usr/lib/|grep libevent如果发现有libevent文件库存在就代表安装完毕。
2 简单的libevent服务器我们通过连接libevent库来进行管理libevent库,所以在使用gcc或者g++编译的时候最后需要加上-levent下面是一个简单的libevent服务器。
#include <stdio.h>#include <string.h>#include <iostream>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>#include <event.h>using namespace std;#define SERVER_ADDR "127.0.0.1"#define SERVER_PORT 8888// 事件basestruct event_base* base;// 读事件回调函数void onRead(int iCliFd, short iEvent, void *arg) {int iLen;char buf[1500];iLen = recv(iCliFd, buf, 1500, 0);if (iLen <= 0) {cout << "Client Close" << endl;// 连接结束(=0)或连接错误(<0),将事件删除并释放内存空间 struct event *pEvRead = (struct event*)arg; event_del(pEvRead);delete pEvRead;close(iCliFd);return;}buf[iLen] = 0;cout << "Client Info:" << buf << endl;struct bufferevent* buf_ev;buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL);buf_ev->wm_read.high = 4096;char MESSAGE[]="welcome to server..";bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));}// 连接请求事件回调函数void onAccept(int iSvrFd, short iEvent, void *arg){int iCliFd;struct sockaddr_in sCliAddr;socklen_t iSinSize = sizeof(sCliAddr);iCliFd = accept(iSvrFd, (struct sockaddr*)&sCliAddr,&iSinSize);// 连接注册为新事件 (EV_PERSIST为事件触发后不默认删除)struct event *pEvRead = new event;event_set(pEvRead, iCliFd, EV_READ|EV_PERSIST, onRead, pEvRead);event_base_set(base, pEvRead);event_add(pEvRead, NULL);struct bufferevent* buf_ev;buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL); buf_ev->wm_read.high = 4096;char MESSAGE[]="welcome to server..";bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));cout<<"a client connect:"<<iCliFd<<endl;}int main(){int iSvrFd;struct sockaddr_in sSvrAddr;memset(&sSvrAddr, 0, sizeof(sSvrAddr));sSvrAddr.sin_family = AF_INET;sSvrAddr.sin_addr.s_addr = inet_addr(SERVER_ADDR); sSvrAddr.sin_port = htons(SERVER_PORT);// 创建tcpSocket(iSvrFd),监听本机8888端口iSvrFd = socket(AF_INET, SOCK_STREAM, 0);bind(iSvrFd, (struct sockaddr*)&sSvrAddr,sizeof(sSvrAddr));listen(iSvrFd, 10);// 初始化basebase = (struct event_base*)event_init();struct event evListen;// 设置事件event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, onAccept, NULL);// 设置为base事件event_base_set(base, &evListen);// 添加事件event_add(&evListen, NULL);// 事件循环event_base_dispatch(base);return 0;}通过编译指令g++ server.cpp -o server -Wall -g -I ./ -levent得到可执行程序./server启动。
libevent 定时器工作原理
libevent定时器工作原理1. 简介libevent是一个事件驱动的网络编程库,它提供了对I/O多路复用、定时器和信号处理等功能的封装。
其中,定时器是libevent中非常重要的一个组件,它可以用于实现各种定时任务,比如定时执行某个函数或发送心跳包等。
本文将详细介绍libevent定时器的工作原理,包括定时器的创建、设置回调函数、启动和停止定时器等过程。
同时,我们还会讨论libevent定时器的底层实现原理,以及如何处理定时器事件。
2. libevent定时器的创建在使用libevent定时器之前,我们首先需要创建一个定时器对象。
libevent提供了event_new函数来创建定时器对象,其函数原型如下:struct event *event_new(struct event_base *base, evutil_socket_t fd, short eve nts, event_callback_fn callback, void *arg);参数说明: - base:事件的基础结构体,表示事件所属的事件处理器。
- fd:定时器的文件描述符,由于定时器不与具体的文件描述符关联,因此可以传入-1。
- events:事件类型,定时器的事件类型为EV_TIMEOUT,表示定时器超时事件。
- callback:事件回调函数,当定时器超时时会调用该函数。
- arg:回调函数的参数。
通过调用event_new函数,我们可以得到一个定时器对象,接下来我们需要设置定时器的超时时间和回调函数。
3. libevent定时器的设置在创建定时器对象后,我们需要使用event_add函数来设置定时器的超时时间和回调函数,将定时器添加到事件处理器中。
int event_add(struct event *ev, const struct timeval *timeout);参数说明: - ev:定时器对象。
libev事件库详解(二)
libev事件库详解(⼆)事件库之Libev(⼀)使⽤Libev#include<ev.h>#include <stdio.h>#include <signal.h>#include <sys/unistd.h>ev_io io_w;ev_timer timer_w;ev_signal signal_w;void io_action(struct ev_loop *main_loop,ev_io *io_w,int e){int rst;char buf[1024] = {'\0'};puts("in io cb\n");read(STDIN_FILENO,buf,sizeof(buf));buf[1023] = '\0';printf("Read in a string %s \n",buf);ev_io_stop(main_loop,io_w);}void timer_action(struct ev_loop *main_loop,ev_timer *timer_w,int e){puts("in tiemr cb \n");ev_timer_stop(main_loop,timer_w);}void signal_action(struct ev_loop *main_loop,ev_signal signal_w,int e){puts("in signal cb \n");ev_signal_stop(main_loop,signal_w);ev_break(main_loop,EVBREAK_ALL);}int main(int argc ,char *argv[]){struct ev_loop *main_loop = ev_default_loop(0);ev_init(&io_w,io_action);ev_io_set(&io_w,STDIN_FILENO,EV_READ);ev_init(&timer_w,timer_action);ev_timer_set(&timer_w,2,0);ev_init(&signal_w,signal_action);ev_signal_set(&signal_w,SIGINT);ev_io_start(main_loop,&io_w);ev_timer_start(main_loop,&timer_w);ev_signal_start(main_loop,&signal_w);ev_run(main_loop,0);return0;}下⾯对使⽤到的这些API进⾏说明。
Libevent学习——事件主循环
Libevent学习——事件主循环8.1、Libevent的事件主循环主要是通过event_base_loop ()函数完成的,其主要操作如下⾯的流程图所⽰,event_base_loop 所作的就是持续执⾏下⾯的循环。
来看下函数源码:intevent_base_loop(struct event_base *base, int flags){const struct eventop *evsel = base->evsel;//多路复⽤IOstruct timeval tv;struct timeval *tv_p;int res, done, retval = 0;EVBASE_ACQUIRE_LOCK(base, th_base_lock);if (base->running_loop) {//检测event_base_loop是否已经运⾏,每个event_base只有⼀个event_base_loopevent_warnx("%s: reentrant invocation. Only one event_base_loop"" can run on each event_base at once.", __func__);EVBASE_RELEASE_LOCK(base, th_base_lock);return -1;}base->running_loop = 1;clear_time_cache(base);//清空时间缓存if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)evsig_set_base(base);// evsignal_base是全局变量,在处理signal时,⽤于指名signal所属的event_base实例done = 0;#ifndef _EVENT_DISABLE_THREAD_SUPPORTbase->th_owner_id = EVTHREAD_GET_ID();#endifbase->event_gotterm = base->event_break = 0;while (!done) {// 事件主循环base->event_continue = 0;if (base->event_gotterm) {break;// 查看是否需要跳出循环,程序可以调⽤event_loopexit_cb()设置event_gotterm标记}if (base->event_break) {break;// 调⽤event_base_loopbreak()设置event_break标记}// 校正系统时间,如果系统使⽤的是⾮MONOTONIC时间,⽤户可能会向后调整了系统时间// 在timeout_correct函数⾥,⽐较last wait time和当前时间,如果当前时间< last wait time// 表明时间有问题,这是需要更新timer_heap中所有定时事件的超时时间。
libevent源码深度剖析
libevent源码深度剖析第⼀章1,前⾔Libevent是⼀个轻量级的开源⾼性能⽹络库,使⽤者众多,研究者更甚,相关⽂章也不少。
写这⼀系列⽂章的⽤意在于,⼀则分享⼼得;⼆则对libevent代码和设计思想做系统的、更深层次的分析,写出来,也可供后来者参考。
附带⼀句:Libevent是⽤c语⾔编写的(MS⼤⽜们都偏爱c语⾔哪),⽽且⼏乎是⽆处不函数指针,学习其源代码也需要相当的c语⾔基础。
2,libevent简介上来当然要先夸奖啦,Libevent 有⼏个显著的亮点:=> 事件驱动(event-driven),⾼性能;=> 轻量级,专注于⽹络,不如ACE那么臃肿庞⼤;=> 源代码相当精炼、易读;=> 跨平台,⽀持Windows、Linux、*BSD和Mac Os;=> ⽀持多种I/O多路复⽤技术, epoll、poll、dev/poll、select和kqueue等;=> ⽀持I/O,定时器和信号等事件;=> 注册事件优先级;Libevent已经被⼴泛的应⽤,作为底层的⽹络库;⽐如memcached、Vomit、Nylon、Netchat等等。
Libevent当前的最新稳定版是1.4.13;这也是本⽂参照的版本。
3,学习的好处学习libevent有助于提升程序设计功⼒,除了⽹络程序设计⽅⾯外,Libevent的代码⾥有很多有⽤的设计技巧和基础数据结构,⽐如信息隐藏、函数指针、c语⾔的多态⽀持、链表和堆等等,都有助于提升⾃⾝的程序功⼒。
程序设计不⽌要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。
只对libevent本⾝的框架⼤概了解,那或许仅仅是⼀知半解,不深⼊代码分析,就难以了解其设计的精巧之处,也就难以为⾃⼰所⽤。
事实上Libevent本⾝就是⼀个典型的Reactor模型,理解Reactor模式是理解libevent的基⽯;因此下⼀节将介绍典型的事件驱动设计模式——Reactor模式。
libevent源码分析
libevent源码深度剖析张亮Email: sparling.liang@回想刚开始写时,就冠以“深度剖析”的名称,也是为了给自己一些压力,以期能写好这一系列文章,对libevent源代码的各方面作详细的分析;现在看来也算是达到了最初的目的。
希望能给学习和使用libevent的朋友们有所帮助。
Email:sparkling.liang@张亮目录libevent源码深度剖析 (1)目录 (3)一序幕 (5)1 前言 (5)2 Libevent简介 (5)3 学习的好处 (5)二Reactor模式 (6)1 Reactor的事件处理机制 (6)2 Reactor模式的优点 (6)3 Reactor模式框架 (6)4 Reactor事件处理流程 (8)5 小结 (9)三基本使用场景和事件流程 (10)1 前言 (10)2 基本应用场景 (10)3 实例代码 (11)4 事件处理流程 (11)5 小结 (12)四 libevent源代码文件组织 (13)1 前言 (13)2 源代码组织结构 (13)3 小结 (14)五 libevent的核心:事件event (15)1 libevent的核心-event (15)2 libevent对event的管理 (16)3 事件设置的接口函数 (17)4 小结 (18)六初见事件处理框架 (19)1 事件处理框架-event_base (19)2 创建和初始化event_base (20)3 接口函数 (20)4 小节 (23)七事件主循环 (24)1 阶段性的胜利 (24)2 事件处理主循环 (24)3 I/O和Timer事件的统一 (27)4 I/O和Signal事件的统一 (27)5 小节 (27)八集成信号处理 (28)1 集成策略——使用socket pair (28)2 集成到事件主循环——通知event_base (29)4 evsignal_info结构体 (30)5 注册、注销signal事件 (30)5 小节 (31)九集成定时器事件 (32)1 集成到事件主循环 (32)2 Timer小根堆 (33)3 小节 (34)十支持I/O多路复用技术 (35)1 统一的关键 (35)2 设置I/O demultiplex机制 (35)3 小节 (37)十一时间管理 (38)1 初始化检测 (38)2 时间缓存 (38)3 时间校正 (40)4 小节 (41)十二让libevent支持多线程 (42)1 错误使用示例 (42)2 支持多线程的几种模式 (42)3 例子——memcached (43)4 小节 (44)一序幕1 前言Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少。
Libevent源码分析—event_add()
Libevent源码分析—event_add()接下来就是将已经初始化的event注册到libevent的事件链表上,通过event_add()来实现,源码位于event.c中。
event_add()这个函数主要完成了下⾯⼏件事:1.将event注册到event_base的I/O多路复⽤要监听的事件中2.将event注册到event_base的已注册事件链表中3.如果传⼊了超时时间,则删除旧的超时时间,重新设置,并将event添加到event_base的⼩根堆中;如果没有传⼊超时时间,则不会添加到⼩根堆中。
只有步骤1成功,才会执⾏步骤2和3;否则什么都没做,直接返回,保证不会改变event的状态。
从中还可以看到,将event添加到已注册事件链表、添加到⼩根堆、从活跃事件链表移除、从⼩根堆中移除,都是通过两个函数完成的:event_queue_insert()、event_queue_remove()intevent_add(struct event *ev, const struct timeval *tv){struct event_base *base = ev->ev_base; //event所属的event_baseconst struct eventop *evsel = base->evsel; //event_base的I/O多路复⽤机制void *evbase = base->evbase; //event_base的I/O多路复⽤机制int res = 0;//DEBUG log.hevent_debug(("event_add: event: %p, %s%s%scall %p",ev,ev->ev_events & EV_READ ? "EV_READ " : "",ev->ev_events & EV_WRITE ? "EV_WRITE " : "",tv ? "EV_TIMEOUT " : "",ev->ev_callback));assert(!(ev->ev_flags & ~EVLIST_ALL));/** prepare for timeout insertion further below, if we get a* failure on any step, we should not change any state.*///如果传⼊了超时时间并且event不再time⼩根堆上,则在⼩根堆上预留⼀个位置//以保证如果后⾯有步骤失败,不会改变初始状态,保证是个原⼦操作if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {if (min_heap_reserve(&base->timeheap, //min_heap.h1 + min_heap_size(&base->timeheap)) == -1)return (-1); /* ENOMEM == errno */}//如果event不在已注册链表或活跃链表中,//则调⽤evsel->add()注册event事件到I/O多路复⽤监听的事件上if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {res = evsel->add(evbase, ev); //将event注册到监听事件上//注册监听事件成功,则将event注册到已注册事件链表上if (res != -1)event_queue_insert(base, ev, EVLIST_INSERTED); //插⼊}/** we should change the timout state only if the previous event* addition succeeded.*///前⾯操作都成功情况下,才能执⾏下⾯步骤//改变超时状态if (res != -1 && tv != NULL) {struct timeval now;/** we already reserved memory above for the case where we* are not replacing an exisiting timeout.*///EVLIST_TIMEOUT表明event已在定时器堆中//则删除旧的定时器if (ev->ev_flags & EVLIST_TIMEOUT)event_queue_remove(base, ev, EVLIST_TIMEOUT); //移除/* Check if it is active due to a timeout. Rescheduling* this timeout before the callback can be executed* removes it from the active list. *///如果事件是由于超时⽽变成活跃事件//则从活跃事件链表中删除if ((ev->ev_flags & EVLIST_ACTIVE) &&(ev->ev_res & EV_TIMEOUT)) {/* See if we are just active executing thisif (ev->ev_ncalls && ev->ev_pncalls) {/* Abort loop */*ev->ev_pncalls = 0; //调⽤次数清0}//从活跃事件链表移除event_queue_remove(base, ev, EVLIST_ACTIVE); //移除}gettime(base, &now);evutil_timeradd(&now, tv, &ev->ev_timeout); //为event添加超时时间event_debug(("event_add: timeout in %ld seconds, call %p",tv->tv_sec, ev->ev_callback));//将event插⼊到⼩根堆中event_queue_insert(base, ev, EVLIST_TIMEOUT); //插⼊}return (res);}event_queue_insert()该函数根据不同的输⼊队列,即不同的事件,在不同的队列中插⼊,并增加相应的事件计数,更新event状态;EVLIST_INSERTED:在已注册事件链表event_base.eventqueue插⼊EVLIST_ACTIVE:根据event优先级,在活跃事件链表event_base.activequeues[event.ev_pri]插⼊EVLIST_TIMEOUT:在⼩根堆event_base.timeheap中插⼊voidevent_queue_insert(struct event_base *base, struct event *ev, int queue){//如果event已经在活跃链表中,则返回;否则,出错if (ev->ev_flags & queue) {/* Double insertion is possible for active events */if (queue & EVLIST_ACTIVE)return;event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,ev, ev->ev_fd, queue);}if (~ev->ev_flags & EVLIST_INTERNAL)base->event_count++; //增加注册事件数ev->ev_flags |= queue; //改变event状态switch (queue) { //根据不同的输⼊参数队列,选择在不同的事件集合中插⼊case EVLIST_INSERTED: //I/O或Signal事件TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); //在已注册事件链表插⼊break;case EVLIST_ACTIVE: //活跃事件base->event_count_active++; //增加活跃事件数TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], //在活跃事件链表插⼊ev,ev_active_next);break;case EVLIST_TIMEOUT: { //定时器事件min_heap_push(&base->timeheap, ev); //在⼩根堆插⼊break;}default:event_errx(1, "%s: unknown queue %x", __func__, queue);}}event_queue_remove()和event_queue_insert()相对应,这个函数主要根据不同的输⼊参数,从不同的事件集合中删除事件。
libevent evthread_use_pthreads
libevent evthread_use_pthreads题目:深入探究libevent中的evthread_use_pthreads引言:在计算机领域中,多线程编程是一种常见且重要的技术,在提高程序并发性、提升计算效率方面发挥着关键作用。
libevent是一款广泛应用于网络编程的开源软件库,通过提供事件驱动、可移植的网络服务器和客户端功能,简化了开发者的工作。
本文将着重深入探究libevent中的evthread_use_pthreads函数,这个函数用于在多线程环境中利用pthreads库实现线程并发。
第一部分:libevent概述1.1 何为libevent?libevent是一个开源软件库,为网络应用提供了一个事件驱动编程接口,可用于基于事件的网络服务器和客户端的开发。
它支持多种事件类型,包括套接字、文件、时间以及信号等。
通过使用libevent,开发者可以编写高度并发性的网络服务器,充分利用计算机资源,提高服务器性能。
1.2 libevent的优势- 事件驱动:libevent基于事件回调机制,即在特定事件发生时,自动调用相应函数进行处理。
- 可移植性:libevent采用了模块化设计,并提供了平台无关的API,因此可以轻松移植到不同的操作系统上。
- 高性能:利用事件驱动的方式,libevent可以高效处理大量并发连接,提供了高性能的网络编程能力。
第二部分:evthread_use_pthreads函数介绍2.1 函数定义在libevent中,evthread_use_pthreads函数用于在多线程环境中利用pthreads库实现线程并发。
其定义如下:cint evthread_use_pthreads(void)2.2 函数功能evthread_use_pthreads函数的主要功能是使libevent能够在多线程环境中使用pthreads库提供的线程功能。
通过调用该函数,开发者可以在libevent中使用线程相关的函数和特性。
libevent介绍
libevent介绍通常我们在建立服务器的处理模型的时候,主要是下面集中模型;(1) a new Connection 进来,用 fork() 产生一个 Process 处理。
(2) a new Connection 进来,用 pthread_create() 产生一个 Thread 处理。
(3) a new Connection 进来,丢入 Event-based Array,由 Main Process 以 Nonblocking 的方式处理所有的 I/O。
这三种方法当然也都有各自的缺点:用 fork() 的问题在于每一个 Connection 进来时的成本太高,如果同时接入的并发连接数太多容易进程数量很多,进程之间的切换开销会很大,同时对于老的内核(Linux)会产生雪崩效应。
用 Multi-thread 的问题在于 Thread-safe 与 Deadlock 问题难以解决,另外有 Memory-leak 的问题要处理,这个问题对于很多程序员来说无异于恶梦,尤其是对于连续服务器的服务器程序更是不可以接受。
如果才用 Event-based 的方式在于实做上不好写,尤其是要注意到事件产生时必须 Nonblocking,于是会需要实做 Buffering 的问题,而 Multi-thread 所会遇到的 Memory-leak 问题在这边会更严重。
而在多 CPU 的系统上没有办法使用到所有的 CPU resource。
北大青鸟中关村。
针对上面存在的问题,通常采用的方法有: 以 Poll 的方式解决:当一个Process 处理完一个 Connection 后,不直接死掉,而继续回到 accept() 的状态继续处理,但这样会遇到 Memory-leak 的问题,于是采用这种方式的人通常会再加上「处理过 N 个 Connection 后死掉,北大青鸟中关村由 Parent Process 再 fork() 一只新的」。
libevent evthread_use_pthreads -回复
libevent evthread_use_pthreads -回复libevent是一个开源的事件驱动编程库,用于在网络应用中处理并发事件。
它提供了跨平台的、高性能的事件处理机制,可以用于开发高效的网络服务器和客户端应用程序。
其中的evthread_use_pthreads函数是libevent 库中的一个函数,用于指定使用pthreads作为并发处理的线程模型。
本文将详细介绍libevent和evthread_use_pthreads函数,以及如何使用它来构建高并发的网络应用程序。
一、libevent简介libevent是一个基于事件驱动的编程库,最初由Niels Provos和Nick Mathewson于2000年开发。
它提供了跨平台的API,可以在各种操作系统上运行。
libevent的目标是提供一种简单、高效的方式来处理并发事件,无论是网络应用还是其他类型的应用,都可以通过libevent来实现高性能和可伸缩性。
libevent的核心概念是事件循环(event loop)机制。
在libevent中,所有的I/O操作都被转化为事件,应用程序通过注册回调函数来处理这些事件。
当一个事件发生时,libevent会将其分发给相应的回调函数进行处理。
这种事件驱动的方式使得应用程序可以同时处理多个并发事件,而不需要为每个事件创建一个独立的线程。
libevent提供了一系列的函数和数据结构来支持事件处理。
它可以处理各种类型的事件,包括网络I/O事件、定时器事件、信号事件等。
通过注册合适的回调函数,应用程序可以根据需要处理不同类型的事件。
二、evthread_use_pthreads函数evthread_use_pthreads函数是libevent库中的一个函数,用于指定使用pthreads作为并发处理的线程模型。
具体来说,它将libevent的并发处理模型设置为使用pthread线程库来创建和管理线程。
libevent源码event_config_new(),event_base_new_w。。。
libevent源码event_config_new(),event_base_new_w。
struct event_config *event_config_new(void);/**Allocates a new event configuration object. 分配⼀个新的event_config对象The event configuration object can be used to change the behavior ofan event base. event_config对象可以⽤于更改event base的⾏为@return an event_config object that can be used to store configuration, orNULL if an error is encountered. 返回⼀个event_config 对象,由于存储配置,当发⽣错误返回NULL@see event_base_new_with_config(), event_config_free(), event_config*/struct event_base *event_base_new_with_config(const struct event_config *);/**Initialize the event API. 初始化event接⼝Use event_base_new_with_config() to initialize a new event base, takingthe specified configuration under consideration. The configuration objectcan currently be used to avoid certain event notification mechanisms. 通过event_base_new_with_config(),使⽤指定位置的配置来初始化⼀个新的event base.使⽤的配置对象可⽤于避免默写事件通知机制。
libevent 编译
libevent 编译libevent 是一个开源的、轻量级的事件驱动库,被广泛用于网络服务器和应用程序开发中。
它提供了一个简单而高效的方式来处理并发网络连接和事件驱动编程。
本文将介绍libevent的基本概念、特性和使用方法。
一、libevent的基本概念1. 事件循环:libevent的核心是事件循环,它负责监听和分发事件。
事件循环可以理解为一个无限循环,不断地等待事件的发生并处理它们。
2. 事件:事件是指一个特定的操作或状态,可以是网络连接建立、数据可读、定时器到期等。
libevent可以监听多种类型的事件,并在事件发生时进行相应的处理。
3. 回调函数:libevent使用回调函数来处理事件。
当某个事件发生时,libevent会调用相应的回调函数来处理该事件。
开发者需要提供回调函数的实现,以定义事件发生时的具体行为。
4. 事件驱动:libevent采用事件驱动的编程模型,即程序通过监听和处理事件来驱动程序的执行。
相比于传统的顺序执行模型,事件驱动模型更加高效和灵活。
二、libevent的特性1. 跨平台:libevent可以在多种操作系统上运行,包括Linux、Windows、MacOS等,具有良好的跨平台性。
2. 高性能:libevent采用非阻塞的IO模型,能够处理大量并发连接,具有出色的性能表现。
3. 多种网络协议支持:libevent支持TCP、UDP、HTTP等多种网络协议,可以满足不同应用场景的需求。
4. 定时器支持:libevent提供了定时器功能,可以方便地实现定时任务的调度。
5. 可扩展性:libevent的设计非常灵活,可以方便地扩展和定制,满足各种复杂的需求。
三、使用libevent进行事件驱动编程1. 初始化libevent:使用event_base_new()函数初始化一个事件基础结构体,并通过event_base_dispatch()函数进入事件循环。
2. 创建事件:使用event_new()函数创建一个事件,并指定事件类型和相关的回调函数。
libevent源码解析
libevent源码解析libevent是一个事件触发型的网络通信库,它主要用于实现高效、可扩展、高并发的网络通信,广泛应用于服务器程序的开发中。
libevent源码可运行于Windows、Linux等操作系统,并提供了C、C++、Python等多种语言接口,被广泛应用于各种网络通信场景。
libevent源码的主要结构及功能libevent的设计基于事件驱动的思想,实现了高效的异步非阻塞I/O模型。
它能够有效地处理大量的并发连接请求,支持多种协议、多路复用、定时器、信号处理等功能,是一个功能强大、易于扩展的网络通信库。
其源码主要包括以下几个重要的结构和功能:1. event_base:这是libevent的核心结构,他负责管理和调度所有事件,包括I/O事件、信号事件、定时器事件等。
event_base可以同时处理多个不同类型的事件,并且支持事件优先级和超时事件的处理。
libevent库中所有其他的结构都需要与event_base关联才能生效。
2. event:event是事件处理的最小单位,它代表一个被监视的文件描述符或是一个信号等。
当文件描述符有数据可读写或者信号触发时,就会触发相应的事件处理程序。
每个event都需要与一个event_base关联,以便能够得到正确的事件调度。
3. evutil:evutil是libevent的基本工具库,主要提供了跨平台的网络编程接口,如字符串操作、字符串解析、socket地址解析等。
evutil是libevent实现的基础库,所有其他高层次的实现都依赖于它。
4. bufferevent:这是一个对I/O进行封装的结构,用于处理基于缓存的I/O通信、数据包的发送和接收等功能。
它可以自动处理TCP流的拆分和合并,同时实现了读写缓冲区管理、超时和错误处理等功能。
5. timeval:这是一个时间相关的结构,主要用于管理事件的超时处理和事件的定时器操作。
libevent中事件操作的时间精度为微秒级。
libev源码解析
libev源码解析⼀ libev简介 libev是⼀个轻量级的事件通知库,具备⽀持多种事件通知能⼒,通过对libev的源码的阅读,可以清楚了解事件通知实现内部机制。
⼆核⼼数据结构在libev中关键的数据结构是,loop结构体,该结构体定义的字段较多,但是主要核⼼的可以分为两⼤类ev_loop结构体(loop为ev_loop结构的全局变量)的字段定义在ev_vars.h头⽂件中,然后在ev.c中通过include的⽅式导⼊1.各类事件的watcher集合 loop中有⽀持很多类型的事件,如下ev_io // IO可读可写ev_stat // ⽂件属性变化ev_signal // 信号处理ev_timer // 相对定时器ev_periodic // 绝对定时器ev_child // ⼦进程状态变化ev_fork // fork事件ev_cleanup // event loop退出触发事件ev_idle // event loop空闲触发事件ev_embed // 嵌⼊另⼀个后台循环ev_prepare // event loop之前事件ev_check // event loop之后事件ev_async // 线程间异步事件这些事件的监控管理都对应⼀种类型的watcher数组,⽐如(loop)->anfds :维护所有fd事件(loop)->timers :维护所有的定时器(loop)->periodics:周期性事件(loop)->prepares:该事件是loop启动之间就会执⾏的事件等,每类事件都能在loop结构中找到对应的数组来维护对应的watchers。
2.2 watcher结构对于不同类型的事件的watcher,采⽤继承的⽅式来实现各个类型的watcher,libev是使⽤c的宏定义来实现继承(宏的奇技淫巧在libev中随处可见,这也导致libev看起来⽐较晦涩)这个是公共watcher得到结构,是会被所有的⼦watcher所共享。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
libevent源码深度剖析张亮Email: sparling.liang@回想刚开始写时,就冠以“深度剖析”的名称,也是为了给自己一些压力,以期能写好这一系列文章,对libevent源代码的各方面作详细的分析;现在看来也算是达到了最初的目的。
希望能给学习和使用libevent的朋友们有所帮助。
Email:sparkling.liang@张亮目录libevent源码深度剖析 (1)目录 (3)一序幕 (5)1 前言 (5)2 Libevent简介 (5)3 学习的好处 (5)二Reactor模式 (6)1 Reactor的事件处理机制 (6)2 Reactor模式的优点 (6)3 Reactor模式框架 (6)4 Reactor事件处理流程 (8)5 小结 (9)三基本使用场景和事件流程 (10)1 前言 (10)2 基本应用场景 (10)3 实例代码 (11)4 事件处理流程 (11)5 小结 (12)四libevent源代码文件组织 (13)1 前言 (13)2 源代码组织结构 (13)3 小结 (14)五libevent的核心:事件event (15)1 libevent的核心-event (15)2 libevent对event的管理 (16)3 事件设置的接口函数 (17)4 小结 (18)六初见事件处理框架 (19)1 事件处理框架-event_base (19)2 创建和初始化event_base (20)3 接口函数 (20)4 小节 (23)七事件主循环 (24)1 阶段性的胜利 (24)2 事件处理主循环 (24)3 I/O和Timer事件的统一 (27)4 I/O和Signal事件的统一 (27)5 小节 (27)八集成信号处理 (28)1 集成策略——使用socket pair (28)2 集成到事件主循环——通知event_base (29)4 evsignal_info结构体 (30)5 注册、注销signal事件 (30)5 小节 (31)九集成定时器事件 (32)1 集成到事件主循环 (32)2 Timer小根堆 (33)3 小节 (34)十支持I/O多路复用技术 (35)1 统一的关键 (35)2 设置I/O demultiplex机制 (35)3 小节 (37)十一时间管理 (38)1 初始化检测 (38)2 时间缓存 (38)3 时间校正 (40)4 小节 (41)十二让libevent支持多线程 (42)1 错误使用示例 (42)2 支持多线程的几种模式 (42)3 例子——memcached (43)4 小节 (44)一序幕1 前言Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少。
写这一系列文章的用意在于,一则分享心得;二则对libevent代码和设计思想做系统的、更深层次的分析,写出来,也可供后来者参考。
附带一句:Libevent是用c语言编写的(MS大牛们都偏爱c语言哪),而且几乎是无处不函数指针,学习其源代码也需要相当的c语言基础。
2 Libevent简介上来当然要先夸奖啦,Libevent 有几个显著的亮点:事件驱动(event-driven),高性能;轻量级,专注于网络,不如ACE那么臃肿庞大;源代码相当精炼、易读;跨平台,支持Windows、Linux、*BSD和Mac Os;支持多种I/O多路复用技术,epoll、poll、dev/poll、select和kqueue等;支持I/O,定时器和信号等事件;注册事件优先级;Libevent已经被广泛的应用,作为底层的网络库;比如memcached、V omit、Nylon、Netchat 等等。
Libevent当前的最新稳定版是1.4.13;这也是本文参照的版本。
3 学习的好处学习libevent有助于提升程序设计功力,除了网络程序设计方面外,Libevent的代码里有很多有用的设计技巧和基础数据结构,比如信息隐藏、函数指针、c语言的多态支持、链表和堆等等,都有助于提升自身的程序功力。
程序设计不止要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。
只对libevent本身的框架大概了解,那或许仅仅是一知半解,不深入代码分析,就难以了解其设计的精巧之处,也就难以为自己所用。
事实上Libevent本身就是一个典型的Reactor模型,理解Reactor模式是理解libevent 的基石;因此下一节将介绍典型的事件驱动设计模式——Reactor模式。
参考资料:Libevent: /~provos/libevent/二Reactor模式前面讲到,整个libevent本身就是一个Reactor,因此本节将专门对Reactor模式进行必要的介绍,并列出libevnet中的几个重要组件和Reactor的对应关系,在后面的章节中可能还会提到本节介绍的基本概念。
1 Reactor的事件处理机制首先来回想一下普通函数调用的机制:程序调用某函数 函数执行,程序等待 函数将结果和控制权返回给程序 程序继续处理。
Reactor释义“反应堆”,是一种事件驱动机制。
和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的时间发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。
使用Libevent也是想Libevent框架注册相应的事件和回调函数;当这些时间发声时,Libevent会调用这些回调函数处理相应的事件(I/O读写、定时和信号)。
用“好莱坞原则”来形容Reactor再合适不过了:不要打电话给我们,我们会打电话通知你。
举个例子:你去应聘某xx公司,面试结束后。
“普通函数调用机制”公司HR比较懒,不会记你的联系方式,那怎么办呢,你只能面试完后自己打电话去问结果;有没有被录取啊,还是被据了;“Reactor”公司HR就记下了你的联系方式,结果出来后会主动打电话通知你:有没有被录取啊,还是被据了;你不用自己打电话去问结果,事实上也不能,你没有HR的留联系方式。
2 Reactor模式的优点Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:1)响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;3)可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;4)可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;3 Reactor模式框架使用Reactor模型,必备的几个组件:事件源、Reactor框架、多路复用机制和事件处理程序,先来看看Reactor模型的整体框架,接下来再对每个组件做逐一说明。
1)事件源Linux上是文件描述符,Windows上就是Socket或者Handle了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。
2)event demultiplexer——事件多路分发机制由操作系统提供的I/O多路复用机制,比如select和epoll。
程序首先将其关心的句柄(事件源)及其事件注册到event demultiplexer上;当有事件到达时,event demultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”;程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。
对应到libevent中,依然是select、poll、epoll等,但是libevent使用结构体eventop进行了封装,以统一的接口来支持这些I/O多路复用机制,达到了对外隐藏底层系统机制的目的。
3)Reactor——反应器Reactor,是事件管理的接口,内部使用event demultiplexer注册、注销事件;并运行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。
对应到libevent中,就是event_base结构体。
一个典型的Reactor声明方式class Reactor{public:int register_handler(Event_Handler *pHandler, int event);int remove_handler(Event_Handler *pHandler, int event);void handle_events(timeval *ptv);// ...};4)Event Handler——事件处理程序事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供Reactor在相应的事件发生时调用,执行相应的事件处理。
通常它会绑定一个有效的句柄。
对应到libevent中,就是event结构体。
下面是两种典型的Event Handler类声明方式,二者互有优缺点。
class Event_Handler{public:virtual void handle_read() = 0;virtual void handle_write() = 0;virtual void handle_timeout() = 0;virtual void handle_close() = 0;virtual HANDLE get_handle() = 0;// ...};class Event_Handler{public:// events maybe read/write/timeout/close .etcvirtual void handle_events(int events) = 0;virtual HANDLE get_handle() = 0;// ...};4 Reactor事件处理流程前面说过Reactor将事件流“逆置”了,那么使用Reactor模式后,事件控制流是什么样子呢?可以参见下面的序列图。
5 小结上面讲到了Reactor的基本概念、框架和处理流程,对Reactor有个基本清晰的了解后,再来对比看libevent就会更容易理解了,接下来就正式进入到libevent的代码世界了,加油!参考资料:Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects, V olume 2三基本使用场景和事件流程1 前言学习源代码该从哪里入手?我觉得从程序的基本使用场景和代码的整体处理流程入手是个不错的方法,至少从个人的经验上讲,用此方法分析libevent是比较有效的。