zoukankan      html  css  js  c++  java
  • epoll在fork子进程中的问题

    epoll_create 创建的 文件描述符和其他文件描述符一样,是被fork出的子进程继承的,那也就是子进程可以使用这个epoll fd添加感兴趣的io(epoll_ctl),然后是可以影响到父进程的epoll_wait。比如,子进程中注册了一个io写事件后,因为某种原因挂起来了,导致父进程的epoll_wait频繁返回,CPU占用率飙升。看下下面的演示代码:


        void DoWrite(int epollfd) {
      5     int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
      6     if (fd < 0) {
      7         perror("socket ");
      8         exit(-1);
      9     }
    10     struct sockaddr_un peer_addr;
    11     memset(&peer_addr, 0, sizeof(peer_addr));
    12     peer_addr.sun_family = AF_LOCAL;
    13     const char *ipc_path =  "/home/longzhiri/my_code/nettest/localnettest.ipc";
    14     strncpy(peer_addr.sun_path, ipc_path, sizeof(peer_addr.sun_path)-1);
    15     if (connect(fd, (struct sockaddr *)&peer_addr,  SUN_LEN(&peer_addr))<0){
    16         perror("connect ");
    17         exit(-1);
    18     }
    19     struct epoll_event ev, events[10];
    20     ev.events = EPOLLOUT;
    21     ev.data.fd = fd;
    22     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
    23         perror("epoll_ctl");
    24         exit(-1);
    25     }
    26
    27     sleep(10);
    28     epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
    29     printf("child process exit ");
    30 }
    31
    32 int main(int argc, char *argv[]) {
    33     int epollfd = epoll_create(10);
    34     if (epollfd < 0) {
    35         perror("epoll_create");
    36         return -1;
    37     }
    38
    39     struct epoll_event events[10];
    40     int pid = fork();
    41     if (pid < 0) {
    42         perror("fork");
    43         return -1;
    44     } else if (pid > 0) {
    45         for (;;) {
    46             int nfds = epoll_wait(epollfd, events, 10, -1);
    47             if (nfds < 0) {
    48                 perror("epoll_wait 1");
    49                 return -1;
    50             }
    51             printf("wake up +++ ");
    52         }
    53     } else {
    54         DoWrite(epollfd);
    55     }
    56     return 0;
    57 }
                                   
    真实环境看起来很难犯这种错误,但其实在使用第三方库的时候,因为隐藏不少逻辑,犯错的概率就高了。比如在使用libevent的时候,fork出的子进程想要复用父进程的event_base是必需调用event_reinit的,但是不了解这个问题的人就会直接拿父进程的event_base来使用。看下event_reinit的代码,底层使用了epoll的重新epoll_create出一个epollfd的,而不是重用父进程的,也就是没有调用event_reinit,注册的读写事件,其实都是在父进程中那个epoll_wait那里返回。
  • 相关阅读:
    Java7 和 Java8 中的 ConcurrentHashMap 原理解析
    Java 7 和 Java 8 中的 HashMap原理解析
    “三次握手,四次挥手”你真的懂吗?
    互联网面试必杀:如何保证消息中间件全链路数据100%不丢失:第四篇
    互联网面试必杀:如何保证消息中间件全链路数据100%不丢失:第三篇
    互联网面试必杀:如何保证消息中间件全链路数据100%不丢失:第二篇
    互联网面试必杀:如何保证消息中间件全链路数据100%不丢失:第一篇
    面试中被问Spring循环依赖的三种方式!!!
    Elasticsearch 技术分析(六): 自动发现机制
    Elasticsearch 技术分析(四): 分布式工作原理
  • 原文地址:https://www.cnblogs.com/persistentsnail/p/3390839.html
Copyright © 2011-2022 走看看