epoll与fork
使用epoll时,如果在调用epoll_create之后,调用了fork创建子进程,那么父子进程虽然有各自epoll实例的副本,但是在内核中,它们引用的是同一个实例。子进程向自己的epoll实例添加、修改和删除文件描述符时,是可以影响到父进程的epoll_wait的。所以会发生意想不到的问题,分情况看一下:
1:向子进程中的epoll实例添加描述符,描述符事件触发后,也会影响到父进程的epoll实例,代码如下:
#define MAXEVENTS 20 int listenfd;
struct epoll_event events[MAXEVENTS]; int epfd = epoll_create(MAXEVENTS); if((pid = fork()) < 0) return; if(pid == 0)
{
listenfd = socketfd();
struct epoll_event lisevent;
lisevent.events = EPOLLIN;
lisevent.data.fd = listenfd; res = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &lisevent);
} while(1)
{
res = epoll_wait(epfd, events, MAXEVENTS, -1); for(i = 0; i < res; i++)
{
connectfd = accept(events[i].data.fd, (struct sockaddr *)&clientaddr, (socklen_t *)&addrlen);
if(connectfd < 0)
{
perror("accept error");
continue;
}
printf("connect from %s\n", inet_ntop(AF_INET, &(clientaddr.sin_addr), addrbuf, 20));
close(connectfd);
}
}
上述代码中,在fork之前创建epoll实例,然后在子进程中,创建监听socket,并且加入到epoll实例中。父子进程同时在epoll实例上调用epoll_wait等待连接的到来。如果此时客户端建链,则打印如下:
accept error: Bad file descriptor
accept error: Bad file descriptor
……
accept error: Bad file descriptor
connect from 127.0.0.1
也就是说,连接到来时,尽管是在子进程中创建的监听套接字,加入到子进程中的epoll实例中。但是父子进程中epoll实例都会收到触发的事件,二者的epoll_wait都会停止阻塞,开始调用accept。
父进程调用accept失败,打印出Bad file descriptor错误,是因为在父进程中,根本没有监听套接字。所以,只要子进程没有调用accept成功,则该连接事件就会一直触发,从而父进程一直打印accept错误信息,直到子进程调用accept成功,打印出connect from 127.0.0.1。
2:在fork之前,创建epoll实例、监听套接字listenfd,并将listenfd加入到epoll实例中。然后父子进程一起等待事件的触发,代码如下:
#define MAXEVENTS 20 int listenfd;
struct epoll_event events[MAXEVENTS]; int epfd = epoll_create(MAXEVENTS); listenfd = socketfd();
struct epoll_event lisevent;
lisevent.events = EPOLLIN;
lisevent.data.fd = listenfd; res = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &lisevent); if((pid = fork()) < 0) return; while(1)
{
res = epoll_wait(epfd, events, MAXEVENTS, -1); for(i = 0; i < res; i++)
{
printf("[%s]before accept\n", pid?"father":"child");
connectfd = accept(events[i].data.fd, (struct sockaddr *)&clientaddr, (socklen_t *)&addrlen);
printf("[%s]after accept\n", pid?"father":"child"); if(connectfd < 0)
{
perror("accept error");
continue;
}
printf("connect from %s\n", inet_ntop(AF_INET, &(clientaddr.sin_addr), addrbuf, 20));
close(connectfd);
}
}
上述代码在fork之前创建好epoll实例和监听套接字,然后调用fork,父子进程在各自的epoll实例上等待事件的发生,如果此时到来了一个客户端连接,则打印如下:
[father]before accept
[father]after accept
connect from 127.0.0.1
[child]before accept
可见,到来的连接触发的事件,会同时通告给被父子进程的epoll实例。父进程调用accept得到该连接,而子进程调用accept时,连接已经被取走了,所以子进程中的accept阻塞。
总结:在fork之前创建的epoll实例,尽管分别处于父子进程各自的空间中,但是它们在底层引用的同一个内核结构。所以,当事件发生时,会同时通告给父子进程中的epoll实例。这其实算是epoll设计上的一个缺陷,应该避免在fork之前创建epoll实例,或者在fork之后,关闭原epoll实例,重新创建本进程的epoll实例。这一点在libev的文档中有所提及:
The biggest issue is fork races, however - if a program forks then both parent and child process have to recreate the epoll set, which can take considerable time (one syscall per file descriptor) and is of course hard
to detect.
参考:http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod
epoll与fork的更多相关文章
- epoll在fork子进程中的问题
epoll_create 创建的 文件描述符和其他文件描述符一样,是被fork出的子进程继承的,那也就是子进程可以使用这个epoll fd添加感兴趣的io(epoll_ctl),然后是可以影响到父进程 ...
- C语言可以开发哪些项目?
C语言是我们大多数人的编程入门语言,对其也再熟悉不过了,不过很多初学者在学习的过程中难免会出现迷茫,比如:不知道C语言可以开发哪些项目,可以应用在哪些实际的开发中--,这些迷茫也导致了我们在学习的过程 ...
- 大型分布式C++框架《四:netio之请求包中转站 上》
本来一篇文章就该搞定的.结果要分上下篇了.主要是最近颈椎很不舒服.同时还在做秒杀的需求也挺忙的. 现在不能久坐.看代码的时间变少了.然后还买了两本治疗颈椎的书.在学着,不过感觉没啥用.突然心里好害怕. ...
- C语言可以开发哪些项目?(转)
原文地址:https://www.cnblogs.com/shiyanlou/p/6098661.html 知乎:https://www.zhihu.com/question/20564904 C语言 ...
- 17个C语言可以做的小案例项目
C语言是我们大多数人的编程入门语言,对其也再熟悉不过了,不过很多初学者在学习的过程中难免会出现迷茫,比如:不知道C语言可以开发哪些项目,可以应用在哪些实际的开发中……,这些迷茫也导致了我们在学习的过程 ...
- C 实现有追求的线程池 后续
引言 -_- 还是老套路开局 很久以前写过一个有追求的线程池 -> C 实现有追求的线程池 探究 讲述的是一种思路, 并且实现了. 可以一用. 最近在详细搞simplec 框架. 准备发布个正式 ...
- 用C语言开发的19个经典项目,你会第几个?
前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:实验楼 C语言是我们大多数人的编程入门语言,对其也再熟悉不过了,不过很多 ...
- swoole在线聊天学习笔记
<?php $http=); $http->on('request',function(swoole_http_request $request,swoole_http_response ...
- (转载) Linux IO模式及 select、poll、epoll详解
注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...
随机推荐
- 读书笔记--Head First 设计模式 目录
1.设计模式入门 2.观察者模式 3.装饰者模式 4.工厂模式 5.单件模式 6.命令模式 7.适配器模式与外观模式 8.模板方法模式 9.迭代器与组合模式 10.状态模式 11.代理模式 12.复合 ...
- LintCode_415 有效回文串
给定一个字符串,判断其是否为一个回文串.只包含字母和数字,忽略大小写. 注意事项 你是否考虑过,字符串有可能是空字符串?这是面试过程中,面试官常常会问的问题. 在这个题目中,我们将空字符串判定为有效回 ...
- https方式nginx 代理tomcat访问不带www的域名301重定向跳转到www的域名帮助seo集中权重
比如我要把 http://gucanhui.com http://www.gucanhui.com 跳转到https://www.gucanhui.com 用F12的network可以看到状态码301 ...
- myeclipse10.7的破解 不需要去CSDN付费下载-免csdn费下载
吐槽一下,大票CSDN博主,在博文里基本不放干货,都弄成附件,放在csdn付费下载,一个破解办法,竟然50元,好在我是vip用户,不在乎价格,特此 这篇文章搬运一下资源给大家免费下载 顺便纠正一下其文 ...
- Docker容器中MySQL最大连接数被限制为214的解决方案
原文:Docker容器中MySQL最大连接数被限制为214的解决方案 一.背景 话说笔者在上次的博客里简单的讲了一下调整MySQL最大连接数的方法.在文章的最后笔者提到了还有一些特殊情况比如说Dock ...
- 关于java中的异常
java中有时候要写形如下图中的方法抛出异常 之所以要这么写(要在方法声明行写上throws ...)是因为这种 FileNotFoundException 属于编译异常 不属于运行时异常 不会主动抛 ...
- JS Ajax跨域访问
js ajax跨域访问报"No 'Access-Control-Allow-Origin' header is present on the requested resource 如果请求的 ...
- 2019-9-2-win10-uwp-存放网络图片到本地
title author date CreateTime categories win10 uwp 存放网络图片到本地 lindexi 2019-09-02 12:57:38 +0800 2018-2 ...
- Leetcode79. Word Search单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字 ...
- golang之select
2.switch语句 (1) (2) 3.select语句 4.for语句 (1)常规式 (2)条件式 (3) (4) goto break continue fallthrought ------- ...