ET模式下,需要循环从缓存中读取,直到返回EAGAIN没有数据可读后,一个被通知的事件才算结束。如果还读取过程中,同一个连接又有新的事件到来,触发其他线程处理同一个socket,就乱了。EPOLL_ONESHOT就是用来避免这种情况发生的。将事件设置为EPOLL_ONESHOT后,每次事件触发后就会将这个FD从rbtree中删除,就不会再监听该事件了。

下面是我模仿别人写的一段代码:

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <libgen.h>
#include <assert.h>
#include <stdbool.h> #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <pthread.h> #define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 1024 #define ONE_SHOT true
#define NOT_ONE_SHOT false struct data {
int epollfd;
int sockfd;
}; void setnonblockling(int fd)
{
int fd_option = fcntl(fd, F_GETFL);
fd_option |= O_NONBLOCK;
fcntl(fd, F_SETFL, fd_option);
} void add_fd(int epollfd, int fd, bool flag)
{
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET; //监听可读事件,ET模式
if (flag)
event.events |= EPOLLONESHOT; epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblockling(fd);
} void reset_oneshot(int epollfd, int fd)
{
struct epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
} void *threadMain(void *instance)
{
struct data *data = (struct data *)instance;
int epollfd = data->epollfd;
int sockfd = data->sockfd;
pthread_t pid = pthread_self(); //pid or tid, confused printf("start new thread %u to recv data on fd: %d\n", pid, sockfd);
char buf[BUFFER_SIZE];
memset(buf, , sizeof(buf)); for(;;) {
int n = recv(sockfd, buf, BUFFER_SIZE-, );
if (n == ) {
close(sockfd);
printf("foreiner closed the connection\n");
break;
}
else if (n < ) {
if (errno == EAGAIN) {
reset_oneshot(epollfd, sockfd);
printf("EAGAIN. Read later\n");
break;
}
}
else {
buf[n] = '\0';
printf("thread %u get content: %s\n", pid, buf);
printf("thread %u about to sleep\n", pid);
sleep();
printf("thread %u back from sleep\n", pid);
}
} printf("end thread %u receiving data on fd: %d\n", pid, sockfd);
} int main(int argc, char **argv)
{
if (argc <= ) {
printf("usage: %s port_number [ip_address]\n", basename(argv[]));
return ;
} int ret;
int listenfd;
int port = atoi(argv[]);
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
if (argc == ) {
const char *ip = argv[];
inet_pton(AF_INET, ip, &address.sin_addr);
}
else {
address.sin_addr.s_addr = INADDR_ANY;
}
address.sin_port = htons(port);
printf("port = %d\n", port);
listenfd = socket(PF_INET, SOCK_STREAM, );
assert(listenfd >= ); ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
assert(ret != -); ret = listen(listenfd, );
assert(ret != -); struct epoll_event events[MAX_EVENT_NUMBER];
int epollfd = epoll_create();
assert(epollfd != -); /* 需要反复监听listenfd */
add_fd(epollfd, listenfd, NOT_ONE_SHOT); while() {
int fd_number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -); //设置为永久阻塞
if (fd_number < ) {
perror("epoll wait failed\n");
break;
} for (int i = ; i < fd_number; i++) {
int sockfd = events[i].data.fd;
/* listenfd上有新事件,则创建新的fd,并加入监听队列 */
if (sockfd == listenfd) {
struct sockaddr_in client_addr;
socklen_t client_socklen = sizeof(client_addr);
int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_socklen);
add_fd(epollfd, connfd, ONE_SHOT);
}
else if (events[i].events & EPOLLIN) {
pthread_t tid;
struct data instance;
instance.epollfd = epollfd;
instance.sockfd = sockfd;
/* 一个连接对应一个线程,最好写成threadpool-BlockingQueue模式 */
pthread_create(&tid, NULL, threadMain, (void *)&instance);
}
else {
printf("something else happened\n");
}
}
} close(listenfd);
return ;
}

我理解的epoll(三)多线程模式下的ET的更多相关文章

  1. 多线程模式下高并发的环境中唯一确保单例模式---DLC双端锁

    DLC双端锁,CAS,ABA问题 一.什么是DLC双端锁?有什么用处? 为了解决在多线程模式下,高并发的环境中,唯一确保单例模式只能生成一个实例 多线程环境中,单例模式会因为指令重排和线程竞争的原因会 ...

  2. winform 承载 WCF 注意,可能不是工作在多线程模式下

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMo ...

  3. 用VMWare搭建服务器集群不能上外网的三种模式下对应解决办法

    前言 决心要花费宝贵时间写下这篇心得,是因为从昨天晚上到今天上午被这个VMWare模拟搭建的服务器集群不能上外网的问题搞得很心烦,最后决定跟它杠上了!上午还通过远程连接得到了“空白”同学的帮助,在此表 ...

  4. 个人从源码理解angular项目在JIT模式下的启动过程

    通常一个angular项目会有一个个模块(Module)来管理各自的业务,并且必须有一个根模块(AppModule)作为应用的入口模块,整个应用都围绕AppModule展开.可以这么说,AppModu ...

  5. Epoll在LT和ET模式下的读写方式

    在一个非阻塞的socket上调用read/write函数, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是:EAGAIN: 再试一次, ...

  6. SQLite在多线程环境下的应用

    文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...

  7. 关于一个socket在阻塞模式下是否还可以使用的实验

    想到一个socket在多线程模式下,是否可以同时使用的问题,比如socket A阻塞在recv,而别的线程用socket A send是否能成功,下面上实验代码 void thread_socket( ...

  8. 详解PPP模式下的产业投资基金运作【基金管理】

       详解PPP模式下的产业投资基金运作[基金管理]     点击标题下「搏实资本」可快速关注 搏实资本 研究型的投资机构,实操型的专家团队 ﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌ 一.产业投资基金概述 ...

  9. 理解VMware虚拟机下网络连接的三种模式(如何配置虚拟机上网)

    很多朋友都用vmware来测试不同的系统,我结合自己的经验谈一下对网络设置的理解,不对的地方请指正. bridge:这种方式最简单,直接将虚拟网卡桥接到一个物理网卡上面,和linux下一个网卡 绑定两 ...

随机推荐

  1. uni-app 使用Vuex+ (强制)登录

    一.在项目的根目录下新建一个store文件夹,然后在文件夹下新建一个index.js文件 二.在新建的index.js下引入vue和vuex,具体如下: //引入vue和vuex import Vue ...

  2. Ideal 报错之 Class ** is never used 解决办法

    错误信息: 解决办法: file  ------setting ---------inspections----------Groovy--------------Unuse Declaration  ...

  3. centos6.x一直停留在进度条的问题

    由于屏幕关闭加上长时间没有操作可能导致centos进行深度休眠,此时只能通过电源键来强制重启.可以通过修改X11的配置来禁止休眠,配置文件为/etc/X11/xorg.conf,注意修改此文件前记得备 ...

  4. js 匿名函数 js-函数定义方法

    1.任何函数都是有返回值的,没有返回值的,在某些语言里称之为过程例如PL/SQL 2.js中的函数如果没有return 关键字指明给出的返回值,那么当调用完函数后,会返回“undefined" ...

  5. iOS-意见反馈UITextView的使用+不能输入字符输入

    @interface DMFeedbackViewController ()<UITextViewDelegate,UIAlertViewDelegate>@property (nonat ...

  6. selenium3关于ddt驱动之读取json文件。。。

    from selenium import webdriver import ddt import time import unittest """ DDT(驱动.json ...

  7. spring中的bean的生命周期

    bean的生命周期:bean的创建 —— 初始化 ——销毁的过程 容器管理bean的生命周期,我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期就会调用我们的方法 在xml配置文件中是在 ...

  8. elasticsearch 的post put 方式的对比 setting mapping设置 - 添加查询数据

    1.POST和PUT都可以用于创建 2.PUT是幂等方法,POST不是.所以post用户更新,put用于新增比较合适. 参考:https://yq.aliyun.com/articles/366099 ...

  9. 【转帖】PostgreSQL之 使用扩展Extension

    PostgreSQL之 使用扩展Extension https://www.cnblogs.com/lnlvinso/p/11042677.html 挺好的文章.自己之前没有系统学习过 扩展.. 目前 ...

  10. [转帖]System Dynamic Management Views

    System Dynamic Management Views https://docs.microsoft.com/en-us/sql/relational-databases/system-dyn ...