边沿触发&电平触发
【摘要】 边沿触发&电平触发
//主线程试图占用a锁,但没有立即释放a,而是又去申请b锁。 /* 问题一:为什么没有sleep时还会进入回调函数*/ //加a锁只是保护a锁的资源,可以在加a锁的基础上加b锁,但要使a锁和b锁分别保护不同的临界区,否则就会出现读脏数据。
两种模式下触发事件的次数差很多,LT很多,ET很少,因此ET消耗资源少
LT:即电平触发模式 ...
边沿触发&电平触发
//主线程试图占用a锁,但没有立即释放a,而是又去申请b锁。
/* 问题一:为什么没有sleep时还会进入回调函数*/
//加a锁只是保护a锁的资源,可以在加a锁的基础上加b锁,但要使a锁和b锁分别保护不同的临界区,否则就会出现读脏数据。
两种模式下触发事件的次数差很多,LT很多,ET很少,因此ET消耗资源少
LT:即电平触发模式
void lt(struct epoll_event *events,int number,int epollfd, int listenfd)
{ char buf[BUFFER_SIZE]; for(int i = 0; i < number; i++)//相当于在就绪的事件数组中寻找某fd的连接这个读事件 { int sockfd = events[i].data.fd; if(sockfd == listenfd)//看这些触发的读事件中有没有listenfd这个文件,有的话处理连接 { struct sockaddr_in client_address; socklen_t client_addrlength = sizeof(client_address); int connfd = accept(listenfd,(struct sockaddr*)&client_address,&client_addrlength); addfd(epollfd,connfd,false);//连接完成了,为了实现通讯,将connfd注册到内核事件表 } else if(events[i].events & EPOLLIN)//处理读事件且是注册的事件,读事件无非就是连接和收数据 { printf("event trigger once\n");//检测socket读缓存中还是否存在未读出的数据 memset(buf,'\0',BUFFER_SIZE); int ret = recv(sockfd,buf,BUFFER_SIZE-1,0); if(ret <= 0) { close(sockfd); continue; } printf("get %d bytes of content:%s\n",ret,buf); } else { printf("something else happened\n"); }
- 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
ET:即ET边沿触发模式
void et(struct epoll_event* events,int number,int epollfd,int listenfd)
{ char buf[BUFFER_SIZE]; for(int i = 0; i < number; i++) { int sockfd = events[i].data.fd; if(sockfd == listenfd) { struct sockaddr_in client_address; socklen_t client_addrlength = sizeof(client_address); int connfd = accept(listenfd,(struct sockaddr*)&client_address,&client_addrlength); addfd(epollfd,connfd,true); } else if(events[i].events & EPOLLIN) { printf("event trigger once\n");//检测socket读缓存中还是否存在未读出的数据 memset(buf,'\0',BUFFER_SIZE); int ret = recv(sockfd,buf,BUFFER_SIZE-1,0); if(ret < 0) { /*因为这是边沿触发,有事件就绪就必须处理*/ if((errno == EAGAIN) || (errno == EWOULDBLOCK))//对于非阻塞IO,此条件成立表示数据全部读取完毕,之后epoll就能再次触发sockfd上的EPOLLIN事件,以驱动下一次读操作 { printf("read later\n"); break; } close(sockfd); break; } else if(ret == 0) close(sockfd); else printf("get %d bytes of content:%s\n",ret,buf); } else { printf("something else happened\n"); } }
}
- 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
//将fd上的EPOLLIN事件注册到epollfd指定的内核事件表中,最后一个参数指定是否采用ET模式
void addfd(int epollfd,int fd,bool enable_et)
{ struct epoll_event event;//此数组用于存放要注册的事件,并将这些时间加入内核事件表中 event.data.fd = fd; event.events = EPOLLIN;//读事件 if(enable_et) { event.events |= EPOLLET;//表示是边沿触发事件 } epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);//将填好的事件类型及具体描述符注册到内核事件表中 setnonblocking(fd);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
/*此函数只需要配合一个poll的客户端就可以运行
* 通过结果看出,两种模式下触发事件的次数差很多,LT很多,ET很少,因此ET消耗资源少*/
//将文件描述符设置成非阻塞的*/
int setnonblocking(int fd)
{ int old_option = fcntl(fd,F_GETFL); int new_option = old_option | O_NONBLOCK; fcntl(fd,F_SETFL,new_option); return old_option;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
文章来源: xuesong.blog.csdn.net,作者:内核笔记,版权归原作者所有,如需转载,请联系作者。
原文链接:xuesong.blog.csdn.net/article/details/79210630
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)