边沿触发&电平触发

举报
内核笔记 发表于 2021/06/08 23:26:06 2021/06/08
【摘要】 边沿触发&电平触发 //主线程试图占用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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。