日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

epoll与fork

發布時間:2023/12/19 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 epoll与fork 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? ?使用epoll時,如果在調用epoll_create之后,調用了fork創建子進程,那么父子進程雖然有各自epoll實例的副本,但是在內核中,它們引用的是同一個實例。子進程向自己的epoll實例添加、修改和刪除文件描述符時,是可以影響到父進程的epoll_wait的。所以會發生意想不到的問題,分情況看一下:

?

? ? ? ? ?1:向子進程中的epoll實例添加描述符,描述符事件觸發后,也會影響到父進程的epoll實例,代碼如下:

#define MAXEVENTS 20int 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 20int 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

轉載于:https://www.cnblogs.com/gqtcgq/p/7247110.html

總結

以上是生活随笔為你收集整理的epoll与fork的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。