我理解的epoll(三)多线程模式下的ET
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的更多相关文章
- 多线程模式下高并发的环境中唯一确保单例模式---DLC双端锁
DLC双端锁,CAS,ABA问题 一.什么是DLC双端锁?有什么用处? 为了解决在多线程模式下,高并发的环境中,唯一确保单例模式只能生成一个实例 多线程环境中,单例模式会因为指令重排和线程竞争的原因会 ...
- winform 承载 WCF 注意,可能不是工作在多线程模式下
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMo ...
- 用VMWare搭建服务器集群不能上外网的三种模式下对应解决办法
前言 决心要花费宝贵时间写下这篇心得,是因为从昨天晚上到今天上午被这个VMWare模拟搭建的服务器集群不能上外网的问题搞得很心烦,最后决定跟它杠上了!上午还通过远程连接得到了“空白”同学的帮助,在此表 ...
- 个人从源码理解angular项目在JIT模式下的启动过程
通常一个angular项目会有一个个模块(Module)来管理各自的业务,并且必须有一个根模块(AppModule)作为应用的入口模块,整个应用都围绕AppModule展开.可以这么说,AppModu ...
- Epoll在LT和ET模式下的读写方式
在一个非阻塞的socket上调用read/write函数, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是:EAGAIN: 再试一次, ...
- SQLite在多线程环境下的应用
文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...
- 关于一个socket在阻塞模式下是否还可以使用的实验
想到一个socket在多线程模式下,是否可以同时使用的问题,比如socket A阻塞在recv,而别的线程用socket A send是否能成功,下面上实验代码 void thread_socket( ...
- 详解PPP模式下的产业投资基金运作【基金管理】
详解PPP模式下的产业投资基金运作[基金管理] 点击标题下「搏实资本」可快速关注 搏实资本 研究型的投资机构,实操型的专家团队 ﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌ 一.产业投资基金概述 ...
- 理解VMware虚拟机下网络连接的三种模式(如何配置虚拟机上网)
很多朋友都用vmware来测试不同的系统,我结合自己的经验谈一下对网络设置的理解,不对的地方请指正. bridge:这种方式最简单,直接将虚拟网卡桥接到一个物理网卡上面,和linux下一个网卡 绑定两 ...
随机推荐
- JMeter 不同线程组间变量传递(亲测 ok)
JMeter元件都是有作用域的,而变量大多使用正则表达式提取器,要想在不通过线程组件使用变量参数,则需要设置全部变量 JMeter函数助手就提供了一个函数用于设置全局变量属性,实现的功能类似于在用户自 ...
- Spring Cloud(5):服务路由(Zuul)
Zuul简介 所有微服务之间的调用,都应该通过服务网关进行路由,服务网关充当服务与服务之间的中介.服务网关像交通警察一样指挥交通,将用户引导到目标微服务实例.服务网关还充当着应用程序内所有微服务调用的 ...
- IDEA在引入Maven项目后Dependencies中在出现红色波浪线
解决方法: 移除pom.xml中相关依赖,再重新添加即可. 情况及具体解决方法如下: 1.在Maven Project中 Dependencies 出现红色波浪线,如图所示 2.查询本地仓库:jar包 ...
- Cannon 60D 电池卡在电池槽了,拔不出来怎么办?
事情是这样的,本来好好的电池在电池槽里的,后来拿去充电了,充满后就准备装回去,然后一个不小心,电池掉地上了,就看了一下没摔爆,所以也没特别留意有没有什么地方摔坏摔瘸角,然后就往相机里塞,突然就发现塞不 ...
- kubernetes资源调度
kubernetes默认情况下创建pod调度是由kubernetes scheduler来管理的,但显然有时候还是需要人为介入.根据目前的kubernetes版本来说,有两种自定义资源调度的方式:No ...
- webdriver(处理select下拉框元素)
"""处理下拉框""" from selenium import webdriver from selenium.webdriver.com ...
- 冲刺Noip2017模拟赛6 解题报告——五十岚芒果酱
1.ksum(ksum) [问题描述] Peter喜欢玩数组.NOIP这天,他从Jason手里得到了大小为n的一个正整数 数组. Peter求出了这个数组的所有子段和,并将这n(n+)/2个数降序排序 ...
- 线上Storm的worker,executor,task参数调优篇
问题引入: 线上最近的数据量越来越大,出现了数据处理延迟的现象,观察storm ui的各项数据,发现有大量的spout失败的情况,如下: ------------------------------- ...
- Linux 中文man手册安装
首先需要确认的是有没有安装中文支持,如果没有请安装:#yum groupinstall -y "Chinese Support" 现在下载安装包: wget http://manp ...
- [Cometoj#3 B]棋盘_状压dp
棋盘 题目链接:https://cometoj.com/contest/38/problem/B?problem_id=1535 数据范围:略. 题解: 因为行数特别小,所以$dp$的时候可以状压起来 ...