多线程epoll

问题描述 投票:0回答:6

我正在使用 epoll(边缘触发)和非阻塞套接字创建一个多线程服务器。目前,我正在主线程上创建一个事件循环并等待通知,它可以正常工作
我必须在两种方法之间进行选择以使其成为多线程:

  1. 为每个线程创建一个事件循环,并添加服务器套接字的文件描述符以查找每个线程上的通知。 (这可能吗?我的意思是:epoll 线程安全吗?)
  2. 创建单个事件循环并等待通知。每当收到通知时,都会生成一个线程来处理它。

如果我使用第一种方法,多个线程是否有机会收到同一事件的通知?我该如何处理这种情况?

最好的方法是什么? 谢谢你。

c linux multithreading sockets epoll
6个回答
7
投票

我认为选项 1 更受欢迎,因为非阻塞 IO 的主要目的是避免创建和销毁线程的开销。

以流行的Web服务器nginx为例,它创建多个进程(不是线程)来处理一个句柄上传入的事件,并在子进程中处理事件。它们都共享同一个监听套接字。它与选项 1 非常相似。


3
投票

我也在使用

epoll
编写一个服务器,并且我已经考虑了与您所附的相同的模型。

使用方案1是可以的,但是可能会造成“惊群效应”,可以阅读nginx源码找到解决方案。至于选项2,我认为最好使用线程池,而不是每次生成一个新线程。

您还可以选择以下型号:

主线程/进程:

accept
传入阻塞IO连接,并使用BlockingList将fd发送到其他线程或使用
PIPE
发送到其他进程。

子线程/进程:分别创建

epoll
的实例,并将传入的fd添加到
epoll
中,然后用非阻塞IO处理。


1
投票

每个线程的事件循环是最灵活且高性能的 你应该为每个事件循环创建一个epoll fd,不用担心epoll线程安全问题。


0
投票

epoll是线程安全的,一个好的解决方案是你的主进程停留在accept(2)中,一旦你获得文件描述符,在目标线程的epoll fd中注册该文件描述符,这意味着每个线程都有一个epoll队列,一旦创建了线程,您就在调用 pthread_create(3) 中共享 epoll 文件描述符作为参数,因此当新连接到达时,您可以使用目标线程的 epoll fd 执行 epoll_ctl(...EPOLL_CTL_ADD..)在accept(2)之后创建的新套接字有意义吗?


0
投票

epoll 是线程安全的

希望以下代码可以帮助您

https://github.com/jingchunzhang/56vfs/blob/master/network/vfs_so_r.c


0
投票

每个答案都说 epoll 是线程安全的,但事实并非如此。

在最基本的层面上它确实是线程安全的:在考虑事件时,使用

EPOLLET
将只允许一个线程接收事件,而不使用
EPOLLET
(级别)可能会向多个线程传递相同的事件。

但是,它在调度级别上不是线程安全的:当线程接收到事件时(例如,它会因来自网络的第一个数据包而被唤醒),那么下一个数据包将触发第二个线程将触发的另一个事件捡起。现在您已经有两个线程同时运行以从网络获取数据。人们可以想象几种可能会中断的场景,具体取决于读取模式。除了这种竞争之外,操作系统调度可能会扰乱时间并有利于两个线程之一,当线程需要多次读取时,这会出现问题(例如,它先读取大小,然后读取有效负载)

    

© www.soinside.com 2019 - 2024. All rights reserved.