先说结论:没有用mmap
epoll管理内核事件表用到mmap
了吗?
在内核中,epoll
使用数据结构来管理事件表,而这些数据结构通常不是通过 mmap()
来分配内存的。相反,事件表的内存通常是由内核动态分配的,并由内核来管理和维护。
在Linux中,epoll
并不直接使用mmap
,而是使用mmap
的一种实现方式来提高性能。epoll
是Linux提供的一种事件通知机制,用于高效地处理大量的I/O事件。而mmap
是一种内存映射文件到进程地址空间的机制,它允许进程直接访问文件数据而不需要进行显式的读写操作。
在Linux内核中,epoll
使用了mmap
的一种实现方式来提高性能,具体是通过/proc
文件系统中的epoll
特定文件来映射内核数据结构到用户空间,从而实现高效的事件通知。这种方式使得用户空间应用程序可以直接访问epoll
的内部数据结构,而不需要频繁地进行系统调用,从而提高了epoll
的性能和效率。
总的来说,epoll
并不直接使用mmap
,但在其实现中使用了一种类似mmap
的机制来提高性能。
感兴趣的可以阅读源码
revents = ep_item_poll(epi, &pt);//获取就绪事件 if (revents) { if (__put_user(revents, &uevent->events) || __put_user(epi->event.data, &uevent->data){ list_add(&epi->rdllink, head);//处理失败则重新加入链表 ep_pm_stay_awake(epi); return eventcnt ? eventcnt : -EFAULT; } eventcnt++; uevent++; if (epi->event.events & EPOLLONESHOT) epi->event.events &=EP_PRIVATE_BITS;//EPOLLONESHOT标记的处理 else if (!(epi->event.events & EPOLLET)) { list_add_tail(&epi->rdllink, &ep->rdllist);//LT模式处理 ep_pm_stay_awake(epi); } }
epoll是否线程安全?
在Linux系统中,epoll
本身是线程安全的。epoll
提供的系统调用是线程安全的,这意味着可以在多个线程中同时使用epoll
来管理不同的文件描述符或套接字。多个线程可以同时调用epoll_create()
、epoll_ctl()
和epoll_wait()
等函数,而不会导致竞态条件或数据不一致的问题。
但是,需要注意的是,epoll
的线程安全性仅适用于epoll
本身的操作。如果在多个线程中同时访问同一个文件描述符或套接字,而没有合适的同步机制,那么可能会出现竞态条件或数据不一致的情况。因此,在使用epoll
的多线程程序中,需要确保对共享的资源进行适当的同步,以避免竞态条件:即使使用了ET模式,一个socket上的事件还是可能被触发多次,例如:当一个线程处理一个socket时有新数据写入,此时另外一个线程被唤醒读取这些数据,于是出现了两个线程通过是操作一个socket的情况。EPOLLONESHOT解决了多个线程同时操作一个socket的问题,对于注册了EPOLLONESHOT的事件,操作系统最多触发其上注册的一个可读可写异常事件,且只触发一次。这样,一个线程在操作这个socket时,其他线程不可能有机会操作该socket。但反过来思考,注册了EPOLLONESHOT事件的socket,一旦被某个线程处理完毕,要及时修改为EPOLLIN或其他事件,以确保下次这个socket可读时,其事件能够被触发,进而让其他线程有机会继续处理
总的来说,epoll
本身是线程安全的,但在多线程程序中使用时,需要注意对共享资源的访问进行合适的同步。