多个线程如何操作同一个epoll fd

       自己以前做一个接口服务器时候,这种场景下我的设计是多个线程操作同一个epoll fd。彼时,我的理由是epoll的系列函数是线程安全的。

       当然有人不理解为什么会有多个线程操作同一个epoll fd的情形,这里稍微铺陈一下接口服务器的场景。epoll fd有线程1维护,监听服务端端口的socket的accept出来的acceptor(即新的socket fd)也放在这个epoll fd中。当收到客户端链接请求时候,线程2从连接池connector pool中挑选出来一个connector,connector的作用是转发请求,此时connector会把acceptor缓存起来。如果connector收到回复后,connector会通过acceptor向客户端返回一些数据后,线程2此时需要把acceptor在add进epoll fd中。

      以前我以为epoll fd是多线程安全的,我就直接通过epoll_ctl(epoll fd,acceptor,add)把acceptor放进epoll fd中。

      现在再回首看看,自己是想当然的这样操作了,没有任何依据。孟子曰,“行有不得,反求诸己”。既然自己无法解开困惑,那就求助伟大的man了。通过“man epoll_wait”后,得到这么一句话:

NOTES
       While one thread is blocked in a call to epoll_pwait(), it is possible for another thread to add a file descriptor to the waited-upon epoll instance.  If the new file descriptor becomes ready, it will cause the epoll_wait() call to unblock.

       For a discussion of what may happen if a file descriptor in an epoll instance being monitored by epoll_wait() is closed in another thread, see select(2).

        翻译后就是:如果一个线程正阻塞在epoll_pwait上,此时可能有另外一个线程要把一个socket fd添加到这个epoll fd上,如果这个这个新的socket fd被添加进去后处于ready状态,那么epoll_wait就不会再处于阻塞状态。如果由epoll fd监控的一个socket fd被另外一个线程close掉,此时系统处于何种状态请参考select(2)。通过"man 2 select"后,得到如下一段话:

   Multithreaded applications
       If a file descriptor being monitored by select() is closed in another thread, the result is unspecified.  On some UNIX systems, select() unblocks and returns, with an indication that the file descriptor is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned  and the I/O operations was performed).  On Linux (and some other systems), closing the file descriptor in another thread has no effect on select().  In summary, any application that relies on a particular behavior in this scenario must be considered buggy.

       翻译后,其意义为:如果一个线程中由select管理的socket被另外一个线程close掉,将会发生什么只有天晓得。在一些UNIX系统中,select会结束阻塞态并返回,它会标识这个socket处于ready状态(后面对这个socket的操作会失败,os也会给出错误提示,除非在select返回和进程对这个socket进行读写这段时间段内,os又把同一个socket fd分配出去了)。在linux(和其他同类的系统)上,这种行为不会影响select(即有阻塞态变为非阻塞态)。总之,如果一个程序中这种行为应该被认为是一个bug(就不应有这种行为操作)。

       通过以上两段man大神的神示,除了一个线程在epoll或者select中监控一个socket时候另外一个线程对这个socket进行close这种情况,我就可以认为多个线程操作同一个epoll fd的行为是安全的,即我上面的操作是没有问题的。

       以上是个人愚见,恳请大家批评指正。

       另外严厉谴责诸如推酷“www.tuicool.com”这种垃圾抄袭网站不经本人允许就转载本人blog的行为。







转载于:https://my.oschina.net/alexstocks/blog/308458

### 回答1: 如果多个线程同时使用同一个socket_fd,可能会出现以下问题: 1. 数据混乱:由于多个线程同时向socket_fd写入数据,会导致数据混乱。因为不同线程的写入顺序和速度不同,有可能多个线程的数据在socket中交错出现,导致数据丢失或无法解析。 2. 状态不一致:多个线程同时对同一个socket_fd进行状态修改,可能会导致状态不一致。例如,一个线程关闭了socket_fd,但另一个线程仍然在试图向其写入数据,这会导致异常。 3. 性能问题:如果多个线程同时使用同一个socket_fd,可能会导致性能问题。例如,当多个线程同时写入大量数据时,可能会出现竞争情况,导致性能下降。 为了避免以上问题,建议每个线程都使用独立的socket_fd进行数据读写,并采用线程间通信机制来保持状态一致性。 ### 回答2: 当多个线程同时使用同一个socket_fd时,会出现以下情况: 1. 竞争条件:由于多个线程同时操作同一个socket_fd,可能会导致竞争条件的发生。例如,同时发送数据时,多个线程可能会同时写入数据,导致数据交织在一起,使得接收方无法正确解析数据。 2. 数据错乱:由于多个线程同时发送数据,可能会导致数据错乱的情况出现。例如,线程A发送数据1,线程B发送数据2,但由于没有同步机制,线程A和线程B可能交替发送数据,导致接收方无法按照正确的顺序接收数据。 3. 连接错误:如果多个线程同时执行连接操作,可能会导致连接错误的发生。例如,每个线程都执行connect函数,可能会出现多次连接的情况,导致连接中断或失败。 4. 内存泄漏:如果多个线程同时进行内存操作,可能会导致内存泄漏的问题。例如,多个线程同时进行malloc或free操作,可能会导致内存分配出错或未释放的情况。 为避免以上问题,可以采取以下措施: 1. 使用互斥锁:在多个线程操作同一个socket_fd时,使用互斥锁来保护临界区,确保同一时间只有一个线程操作socket_fd。 2. 使用信号量:通过信号量来控制同时对socket_fd操作,以避免竞争条件的发生。 3. 使用线程池:将socket_fd操作交给线程池来处理,每个线程处理一个特定的任务,以避免多线程同时操作同一个socket_fd。 4. 使用线程特定数据:为每个线程提供一个独立的socket_fd变量,使得每个线程都有自己的socket_fd,并避免线程之间的干扰。 综上所述,多线程同时使用同一个socket_fd可能会出现竞争条件、数据错乱、连接错误和内存泄漏等问题。为解决这些问题,可以采用合适的同步机制和线程管理策略。 ### 回答3: 如果多个线程同时使用同一个socket_fd,可能会出现以下情况: 1. 竞争条件:多个线程同时尝试读取或写入数据时,可能会发生竞争条件。这可能导致数据被错误地读取或写入,导致数据损坏或丢失。 2. 数据混乱:如果多个线程同时读取或写入同一个socket_fd,数据的顺序可能会混乱。例如,如果两个线程同时写入数据,这些数据可能会交错在一起,使服务器端难以正确解析。 3. 状态不一致:多个线程同时使用同一个socket_fd,可能会导致socket_fd的状态不一致。例如,一个线程关闭了socket_fd,而另一个线程仍在尝试使用该socket_fd。 4. 内存泄漏:如果多个线程同时使用同一个socket_fd,可能会导致内存泄漏。例如,如果一个线程分配了内存用于读取数据,但由于另一个线程的写入问题,数据未正确释放。 为了避免这些问题,可以通过以下方法解决: 1. 使用互斥锁:使用互斥锁(mutex)来保护对socket_fd的读写操作,同时只允许一个线程进行访问。 2. 使用条件变量:使用条件变量(condition variable)来协调多个线程对socket_fd的访问,以确保数据的正确读写和顺序。 3. 使用线程池:通过使用线程池,可以限制并发访问socket_fd线程数量,减少竞争条件的发生。 4. 使用异步IO操作:使用异步IO操作(如epoll或select)可以在不同的线程中处理多个socket_fd,而无需使用同一个socket_fd。 总之,为了保证多线程同时使用同一个socket_fd的正确性和可靠性,需要采取合适的同步和并发控制措施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值