Linux内核分析:详解epoll

打印 上一主题 下一主题

主题 634|帖子 634|积分 1902

今天学习的内容是,Linux高并发的核心人物:epoll
写在前面

本篇是我阅读了epoll源码后总结出的内容,统共画了这个思维导图,根据下载链接即可举行下载,epoll的处置惩罚机制会根据不同的Linux内核有不同的操纵,比如说对于红黑树的加锁,在不同的版本加锁的计谋大概会有所不同,我这里阅读的重要是Linux的2.6版本的源码
下载链接

链接: https://pan.baidu.com/s/1hRTh7rSesikisgRUO2GBpA?pwd=utgp 提取码: utgp
思维导图


下面是我在阅读中有一些比较困惑的题目,在这里总结出来:
一些题目

有一种说法是,epoll在举行调用创建的本质,是创建了一个建议的文件系统,这句话该怎样明白?

关于“epoll在举行调用创建的本质,是创建了一个浅显的文件系统”这一说法,我们可以从以下几个方面举行明白:
一、epoll的配景与目的
epoll是Linux内核为处置惩罚大批量文件描述符(File Descriptor,简称FD)而作的改进的poll,是Linux下多路复用IO接口select/poll的增强版本。它的重要目的是在大量并发连接中只有少量活泼的情况下,显著提高系统CPU利用率。
二、epoll的实现机制
内核空间与用户空间:
在Linux系统中,内核空间和用户空间是隔离的。内核空间运行着操纵系统核心,管理着硬件资源,而用户空间则运行着用户程序。
传统的select/poll方法在处置惩罚大量文件描述符时,必要在内核空间和用户空间之间频繁举行数据的复制和转达,这会导致较大的性能开销。
epoll的文件系统:
当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体。这个结构体中包含了红黑树(rb_root rbr)和双向链表(list_head rdlist)等成员。
这些数据结构并不是传统意义上的文件系统结构,但它们被用于在内核中高效地管理和存储epoll相干的事件和文件描述符。
因此,说epoll创建了一个“浅显的文件系统”大概是一种形象的说法,旨在夸大epoll在内核中创建了一个用于管理和存储事件的高效数据结构体系。
红黑树与停当链表:
红黑树用于存储所有添加到epoll中的事件(即必要监控的文件描述符)。如允许以高效地实现事件的添加、删除和查找操纵。
停当链表则用于存储那些已经准备好(即发生了感兴趣的事件)的文件描述符。当epoll_wait被调用时,内核会检查停当链表,并将准备好的事件复制到用户空间。
三、结论
综上所述,“epoll在举行调用创建的本质,是创建了一个浅显的文件系统”这一说法,现实上是指epoll在内核中创建了一个用于高效管理和存储事件的数据结构体系。这个体系虽然不是传统意义上的文件系统,但它通过红黑树和停当链表等数据结构实现了对大量文件描述符的高效管理和事件关照。因此,这种说法在肯定程度上是形象且贴切的。
file_operations结构体中的poll方法,其次是第二点,第二点我能明白,意思就是比如有两个进程都在关心我这个fd,那么此时我就得有关照这两个进程的能力,因此我就得给本身弄一个等待队列头,然后这俩进程就是等待队列的成员,等待我把事件停当后,告诉他俩说,我已经准备好了,然后这俩进程再去关照上层,大概是用户大概其他,告诉他们上层的人说这个进程已经准备好了

被poll的fd的要求
在Linux内核中,几乎所有的设备或文件范例(如字符设备、块设备、网络socket等)都通过一个叫做file_operations的结构体来定义它们的操纵集合。这个结构体包含了各种文件操纵函数,如open、read、write、poll等。当一个进程尝试对一个文件描述符执行某种操纵时,内核会查找该文件描述符对应的file_operations结构体,并调用相应的函数。
file_operations结构体中的poll方法
poll方法是file_operations结构体中的一个紧张成员,它用于检查一个文件描述符是否处于某种特定的状态(如可读、可写、非常等)。当上层应用程序(如用户空间的程序)调用poll或select系统调用来检查多个文件描述符的状态时,内核会遍历这些文件描述符,并对每个文件描述符调用其对应的file_operations结构体中的poll方法。
poll方法的实现必要可以大概准确地反映文件描述符的当前状态,并大概必要将等待该文件描述符状态变革的进程或线程添加到某个等待队列中。如许,当文件描述符的状态发生变革时,内核就可以通过该等待队列来关照所有关心的进程或线程。
等待队列
等待队列是Linux内核中用于实现进程同步和事件关照的一种机制。每个可以等待的资源(如文件描述符、信号量等)都可以有一个或多个等待队列与之关联。当一个进程或线程必要等待某个资源的状态发生变革时,它会将本身的等待队列成员(通常是一个wait_queue_t结构体)添加到该资源的等待队列中,并进入睡眠状态。当资源的状态发生变革时,内核会叫醒等待队列中的一个或多个进程或线程,使它们可以大概继续执行。
在你提到的场景中,如果一个文件描述符(fd)被多个进程或线程通过poll或select系统调用来监视,那么该文件描述符就必要有一个等待队列来存储这些等待者。当文件描述符的状态发生变革时(比方,有新的数据可读或可写),内核会遍历该等待队列,并叫醒所有等待该事件的进程或线程。
总结
因此,被poll的fd的要求重要包括两个方面:一是该文件描述符对应的file_operations结构体中必须实现了poll方法,以便内核可以大概检查其状态;二是该文件描述符必要有一个等待队列来存储等待其状态变革的进程或线程,以便在状态变革时可以大概关照它们。这两个要求共同构成了Linux内核中poll机制的底子,使得上层应用程序可以大概高效地监视多个文件描述符的状态。
这是两个条件,照旧一个条件?这两个条件有没有逻辑关系,比如说是,poll操纵是可以关照消息队列这种,照旧说具备poll操纵和关照监控进程本身的停当情况这两个之间没有关系

现实上,这两个条件可以看作是文件描述符(fd)在支持poll机制时必要满足的两个方面,但它们之间是有逻辑关系的。我们可以如许明白:
第一个条件:文件描述符对应的file_operations结构体中必须实现了poll方法。
这是一个技术上的要求,即文件描述符的底层实现必须提供poll接口,以便内核可以大概调用它来检查文件描述符的状态。
第二个条件:文件描述符必要有一个等待队列来存储等待其状态变革的进程或线程。
这是一个功能上的要求,它涉及到文件描述符怎样与等待其状态变革的进程或线程举行交互。等待队列是实现这一交互的关键机制,它答应文件描述符在状态发生变革时关照所有等待的进程或线程。
逻辑关系:
这两个条件是相互关联的,因为poll方法的实现通常会涉及到等待队列的利用。详细来说,当poll方法被调用时,它大概会检查文件描述符的当前状态,并决定是否必要让调用者(即进程或线程)进入睡眠状态。如果必要,它会将调用者添加到文件描述符的等待队列中。当文件描述符的状态发生变革时,内核会通过等待队列来叫醒所有等待的进程或线程。
因此,可以说poll方法的实现依靠于等待队列的存在,而等待队列则是poll机制可以大概正常工作的底子之一。
关于poll操纵与关照监控进程本身的停当情况:
poll操纵本身并不直接“关照”消息队列或监控进程。相反,它是被监控进程用来检查文件描述符状态的一种方式。当监控进程调用poll时,它现实上是在询问内核:“我关心的这些文件描述符中有没有已经准备好举行读/写/非常处置惩罚等操纵的?”
如果文件描述符的状态已经停当(比方,有数据可读或可写),那么poll会返回相应的信息给监控进程。监控进程随后可以根据这些信息来决定下一步的操纵。
如果文件描述符的状态尚未停当,那么监控进程大概会被添加到文件描述符的等待队列中并进入睡眠状态。当文件描述符的状态发生变革时(即变得停当),内核会通过等待队列来叫醒监控进程,并答应它继续执行。
因此,poll操纵与关照监控进程本身的停当情况之间是有密切关系的,但这种关系是通过内核的等待队列机制来间接实现的。
那我们继续讨论下一个题目,这就意味着,一个文件描述符想要被epoll监控,意味着这个文件描述符对应的方法会合包含了poll如许的系统调用,并且它本身也得有作为队列头关照其他进程的能力,这两个条件是相互契合共同协作,才能保证这个被监控的文件描述符可以大概顺利的告诉epoll,有事件停当,你可以来举行关心了

你的明白非常准确。在Linux内核中,一个文件描述符(fd)如果想要被epoll机制监控,确实必要满足一些条件,这些条件重要涉及到文件描述符怎样与epoll举行交互,并关照其状态变革。详细来说,这两个相互契合、共同协作的条件是:
文件描述符对应的方法会合包含poll或类似的系统调用:
这里的“方法集”现实上是指文件描述符的file_operations结构体,它包含了该文件描述符支持的各种操纵,如open、read、write、poll等。
poll方法(或类似的机制,如select利用的select_file方法)对于epoll来说是至关紧张的,因为epoll必要可以大概检查文件描述符的状态,以确定是否有事件发生。如果文件描述符没有实现poll方法,那么epoll就无法有效地监控它。
文件描述符本身具有作为队列头关照其他进程的能力:
这意味着文件描述符必要维护一个或多个等待队列,用于存储等待其状态变革的进程或线程。当文件描述符的状态发生变革时(如数据可读、可写或发生非常),它可以大概遍历这些等待队列,并叫醒所有等待的进程或线程。
epoll机制利用了这个特性来优化事件关照过程。与传统的poll或select不同,epoll利用了一种更高效的等待队列机制(基于事件驱动),它可以显著减少内核和用户空间之间的上下文切换次数,并提高在高并发场景下的性能。
这两个条件是相互契合、共同协作的。文件描述符通过实现poll方法(或类似的机制)来答应epoll检查其状态,并通过维护等待队列来关照等待的进程或线程。而epoll则利用这些特性来提供一种更加高效、可扩展的事件关照机制。
必要注意的是,虽然epoll在内部利用了与poll或select类似的机制来检查文件描述符的状态,但它在设计上举行了大量的优化,特别是在处置惩罚大量并发连接时。因此,在必要高性能事件关照的场景下,epoll通常是更好的选择。
我们再聊一下这个主动poll fd的进程的要求,这个实在就可以当作是epoll create出来的这个epfd,对于这个fd来说,它所必要具备的基本条件是,可以分配一个成员作为某个指定被监控fd的等待队列的成员,来等待着被监控的这个fd身上有事件停当。其次是,它也要有对应的回调函数,这个回调函数可以大概在满足poll状态的时候被调用

在讨论主动poll fd(现实上在这里我们更大概是指epoll创建的epfd,即事件轮询文件描述符)的进程的要求时,我们必要澄清一些概念并详细探讨这些要求。
epfd(事件轮询文件描述符)
epoll是Linux内核提供的一种高效的I/O事件关照机制,它答应应用程序同时监听多个文件描述符(fd)上的事件,如可读、可写或非常。epoll_create系统调用用于创建一个新的epoll实例,并返回一个文件描述符(epfd),该文件描述符用于后续与epoll相干的操纵。
主动epoll进程的要求
对于利用epoll的进程(我们称之为“主动epoll进程”),它所必要具备的基本条件包括:
可以大概分配和管理等待队列成员:
虽然epoll本身在内核中维护了等待队列来跟踪对特定文件描述符(被监控的fd)感兴趣的事件,但主动epoll进程并不直接分配成员到这些等待队列中。相反,它通过epoll_ctl系统调用向epoll实例(epfd)注册或注销对特定文件描述符的监控,并指定感兴趣的事件范例。
内核会处置惩罚这些注册请求,并在内部维护相应的等待队列和关联的逻辑。
具备处置惩罚事件的回调函数:
主动epoll进程通常不会直接为epoll实例(epfd)本身设置回调函数。相反,它会调用epoll_wait(或epoll_pwait)系统调用来等待一个或多个文件描述符上的事件发生。
当epoll_wait返回时,它会提供一个包含已停当事件的文件描述符列表,以及每个事件的详细范例(如可读、可写)。主动epoll进程必要根据这些信息来决定下一步的操纵,这通常是通过在吸收到事件后执行特定的回调函数或处置惩罚逻辑来实现的。
这些回调函数或处置惩罚逻辑是由主动epoll进程本身定义的,它们根据事件范例和被监控的文件描述符来执行相应的操纵。
总结
因此,对于主动epoll进程来说,它并不必要直接分配成员到某个被监控fd的等待队列中,也不必要为epoll实例(epfd)设置回调函数。相反,它通过epoll_ctl注册对特定文件描述符的监控,并通过epoll_wait等待事件发生,然后根据返回的事件信息执行相应的处置惩罚逻辑。
必要注意的是,虽然这里没有直接提到“回调函数”作为epoll实例(epfd)的属性,但主动epoll进程确实必要定义并执行回调函数或处置惩罚逻辑来响应epoll_wait返回的事件。这些回调函数或处置惩罚逻辑是事件驱动编程模式的核心部分,它们答应主动epoll进程以非壅闭的方式高效地处置惩罚多个I/O事件。
slab分配器是Linux内核中一种高效的内存管理机制,重要用于小块内存的分配和释放。以下是对slab分配器的普通解释:

  • 基本概念
    想象你有很多大小不一的箱子(这些箱子可以明白为内存块),而你必要频繁地从这些箱子中取出或放回一些小物件(这些物件可以看作是内核中的数据结构或对象)。slab分配器就像是一个智能的仓库管理员,它将这些箱子按照大小分类,并为每种大小的箱子创建一个专门的“缓存区”(slab缓存)。当你必要某个大小的小物件时,它会直接从对应的缓存区中快速取出,而不必要去翻找整个仓库。
  • 工作原理
    slab分配器的工作原理可以概括为以下几个步骤:
分类缓存:slab分配器将内存分割成多个“缓存”(cache),每个缓存包含固定大小的对象。这些对象可以是内核中的数据结构、缓冲区或其他小块内存。
快速分配与释放:当内核必要分配一个小块内存时,它会检察对应大小的缓存区中是否有空闲对象。如果有,就直接从缓存区中取出;如果没有,slab分配器会向系统申请新的内存页(通过伙伴系统),并将其划分为多个固定大小的对象,然后添加到缓存区中。当对象不再必要时,它会被释放回对应的缓存区,以便后续重用。
减少内存碎片:通过预分配固定大小的对象,slab分配器可以大概减少内存碎片的产生。内存碎片是指那些无法被有效利用的小块内存空间,它们通常是由于频繁地分配和释放不同大小的内存块而产生的。
提高缓存服从:slab分配器还通过保持对象在缓存行中对齐来提高CPU缓存的利用服从。缓存行是CPU缓存中的最小数据单元,通过将对象对齐到缓存行的界限,可以减少CPU在访问对象时的缓存未掷中次数,从而提高程序的执行服从。
3. 应用场景
slab分配器在Linux内核中被广泛用于必要频繁分配和释放小块内存的场景。比方,当内核必要处置惩罚大量的网络数据包、文件I/O操纵或进程调度时,它会频繁地分配和释放各种数据结构(如套接字缓冲区、文件描述符表项、进程描述符等)。通过利用slab分配器,内核可以更加高效地管理这些小块内存,从而提高系统的整体性能。

  • 总结
    总的来说,slab分配器是Linux内核中一种非常紧张的内存管理机制,它通太过类缓存、快速分配与释放、减少内存碎片和提高缓存服从等方式,为内核提供了一种高效、可靠的方式来管理小块内存。这使得Linux系统可以大概在处置惩罚大量并发请求和复杂使命时保持高性能和稳定性。
slab 分配器是干什么的

slab分配器是Linux内核中一种高效的内存管理机制,重要用于小块内存的分配和释放。以下是对slab分配器的普通解释:

  • 基本概念
    想象你有很多大小不一的箱子(这些箱子可以明白为内存块),而你必要频繁地从这些箱子中取出或放回一些小物件(这些物件可以看作是内核中的数据结构或对象)。slab分配器就像是一个智能的仓库管理员,它将这些箱子按照大小分类,并为每种大小的箱子创建一个专门的“缓存区”(slab缓存)。当你必要某个大小的小物件时,它会直接从对应的缓存区中快速取出,而不必要去翻找整个仓库。
  • 工作原理
    slab分配器的工作原理可以概括为以下几个步骤:
分类缓存:slab分配器将内存分割成多个“缓存”(cache),每个缓存包含固定大小的对象。这些对象可以是内核中的数据结构、缓冲区或其他小块内存。
快速分配与释放:当内核必要分配一个小块内存时,它会检察对应大小的缓存区中是否有空闲对象。如果有,就直接从缓存区中取出;如果没有,slab分配器会向系统申请新的内存页(通过伙伴系统),并将其划分为多个固定大小的对象,然后添加到缓存区中。当对象不再必要时,它会被释放回对应的缓存区,以便后续重用。
减少内存碎片:通过预分配固定大小的对象,slab分配器可以大概减少内存碎片的产生。内存碎片是指那些无法被有效利用的小块内存空间,它们通常是由于频繁地分配和释放不同大小的内存块而产生的。
提高缓存服从:slab分配器还通过保持对象在缓存行中对齐来提高CPU缓存的利用服从。缓存行是CPU缓存中的最小数据单元,通过将对象对齐到缓存行的界限,可以减少CPU在访问对象时的缓存未掷中次数,从而提高程序的执行服从。
3. 应用场景
slab分配器在Linux内核中被广泛用于必要频繁分配和释放小块内存的场景。比方,当内核必要处置惩罚大量的网络数据包、文件I/O操纵或进程调度时,它会频繁地分配和释放各种数据结构(如套接字缓冲区、文件描述符表项、进程描述符等)。通过利用slab分配器,内核可以更加高效地管理这些小块内存,从而提高系统的整体性能。

  • 总结
    总的来说,slab分配器是Linux内核中一种非常紧张的内存管理机制,它通太过类缓存、快速分配与释放、减少内存碎片和提高缓存服从等方式,为内核提供了一种高效、可靠的方式来管理小块内存。这使得Linux系统可以大概在处置惩罚大量并发请求和复杂使命时保持高性能和稳定性。
那对于epoll来说,假如它监视的这个fd上没有配备对应的poll方法,但是现实上,我们知道epoll也不会调用这个poll方法,那这个被监视的fd还可以被epoll监视吗?

对于epoll来说,即使被监视的文件描述符(fd)上没有配备对应的poll方法,这个fd仍然可以被epoll监视。这重要是因为epoll的工作原理与select或poll等传统IO多路复用机制有所不同。
epoll的工作原理
epoll是Linux下的一种IO事件关照机制,它通过利用红黑树(一种自平衡二叉查找树)来管理所有必要监视的文件描述符,这使其在处置惩罚大量文件描述符时更加高效。epoll提供了三个重要的函数:
epoll_create:创建一个epoll实例,返回一个文件描述符(epfd),用于后续操纵。
epoll_ctl:向epoll实例中添加、修改或删除必要监视的文件描述符及其事件范例。
epoll_wait:等待一个或多个文件描述符上发生指定的事件,并将发生事件的文件描述符及其事件范例存储在用户提供的数组中。
epoll与poll方法的关系
epoll并不直接调用文件描述符对应的poll方法(如果有的话)。相反,epoll通过内核中的机制来高效地管理文件描述符和事件关照。当利用epoll监视文件描述符时,文件描述符的状态变革(如可读、可写等)是由内核来跟踪的,而不必要用户空间程序(如通过poll方法)来不断查询。
监视无poll方法的fd
即使一个文件描述符没有配备对应的poll方法,只要它支持IO事件关照(比方,是一个socket或管道等),它就可以被epoll监视。epoll通过内核级别的支持来感知这些文件描述符的状态变革,并将这些变革关照给用户空间程序。
结论
因此,即使被监视的文件描述符上没有配备对应的poll方法,这个fd仍然可以被epoll监视。epoll的高效性重要来自于其在内核中实现的优化,而不是依靠于用户空间中的poll方法。这使得epoll成为处置惩罚大量并发连接和高性能网络编程的优选方案之一。
总体演示

工作情况

epoll工作在应用程序和内核协议栈之间

epoll是在内核协议栈和vfs都有的情况下才有的



  • epoll机制通过内核协议栈来获取网络事件,并举行关照
  • VFS的存在为epoll机制提供了文件描述符管理和操纵支持
数据结构

一个红黑树



  • 现实上是红黑树管理所有的IO,事件停当后调用epoll回调,把IO加入到链表中
一个双向链表



  • 停当列表存储的是停当的socket,所以它应可以大概快速的插入数据
三个核心API



  • int epoll_create(int size)

    • 返回的是epfd

      • 创建链表和红黑树


  • int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)

    • 对于监听事件做修改

      • 新增回调,从红黑树加到链表


  • int epoll_wait(int epfd,struct epoll_event *events,int maxevents,nt timeout);

    • 壅闭等待注册的事件发生,返回事件的数目,并将触发的事件写入events数组中

      • 仅仅观察这个双向链表里有没有数据即可


相干概念

为什么必要epoll



  • 高效处置惩罚大量并发连接
  • 内核与用户空间数据拷贝少
  • 支持边沿触发

    • 只检查一次

  • 支持水平触发

    • 一直关照

select与poll的缺陷



  • 文件描述符数量限制
  • 服从题目
  • 信息不足

    • 不说详细是哪个,必要对所有要监视的文件描述符举行遍历

  • 信号停止

    • select 和 poll 调用可以被信号停止,这大概会导致调用失败

epoll的操纵



  • 原理

    • epoll 在 linux 内核中申请了一个浅显的文件系统

  • 三步

    • 调用 epoll_create 创建一个 epoll 对象(在 epoll 文件系统中给这个句柄分配资源)
    • 调用 epoll_ctl 向 epoll 对象中添加连接的套接字
    • 调用 epoll_wait 网络发生事件的连接

实现原理

内核相干知识



  • 等待队列

    • 队列头(wait_queue_head_t)往往是资源生产者

      • 队列成员(wait_queue_t)往往是资源消费者

    • 当头的资源ready后, 会逐个执行每个成员指定的回调函数,来关照它们资源已经ready了

  • 内核的poll机制条件

    • 被动poll的fd

      • 这个fd所对应的方法会合要有poll的系统调用
      • 这个fd本身可以作为队列头关照监控线程

    • 主动poll的fd

      • 添加到被监控fd的等待队列中
      • 设置相应的回调函数


  • epollfd本身也是个fd, 所以它本身也可以被epoll
epoll_create原理



  • 内核会从 slab 缓存中分配一个 eventpoll 结构体实例,包含红黑树根节点和双向链表
  • 内核会创建一个新的、匿名的文件描述符,并将其与一个特殊的 file 结构体关联起来
  • 将 eventpoll 对象保存在 struct file 的 private_data 指针中
  • 实现 file_operations 结构中的 poll 和 release 操纵

    • poll

      • 检察文件描述符上的事件状态(epoll不消这个,但是为了兼容要初始化)

    • release

      • 释放创建的相干资源


epoll_ctl原理



  • 拷贝 epoll_event 结构到内核空间

    • 必要直接访问这些信息来更新 epoll 实例的状态

  • 检查 fd 是否支持 poll 操纵

    • epoll_ctl 并不直接调用 file_operations 中的 poll 方法,但是为了兼容也得有

  • 获取 event_poll 对象

    • 包含了红黑树、停当链表和其他一些用于管理文件描述符和事件的内部数据结构

  • 根据操纵范例(op)执行添加、删除或修改
  • 初始化等待队列和回调函数

    • 将事件添加到 epoll 的停当链表中,并大概叫醒等待在 epoll_wait 上的进程

  • 调用 file_operations->poll 函数(如果必要)

    • epoll 依靠于本身的机制来检测事件

      • 但是也得初始化poll方法,因为要和前面兼容


  • 将新的epitem结构更新到红黑树中
epoll_wait原理



  • 计算睡眠时间(如果有)
  • 判断 eventpoll 对象的链表是否为空

    • 如果不睡眠,就直接返回有照旧没有

      • 拷贝资源给用户空间


  • 设置进程状态为可睡眠
  • 初始化等待队列(如果有睡眠)

    • 在睡眠时将当前进程添加到该队列中

  • 超时或被叫醒
  • 拷贝资源给用户空间
协议栈通信

协议栈和epoll模块之间的通信是异步的,没有耦合,不必要等待

关照机遇



  • 协议栈三次握手完成,往accept全连接队列里加入这个节点时,关照epoll有事件来了epollin
  • 客户端发了1个数据到协议栈,协议栈此时要返回ack给客户端的这里的机遇,会关照epoll有事件可读 epollin
线程安全

对红黑树加锁(互斥锁)



  • 锁整棵树

    • 全局性操纵

      • 简化同步逻辑(图方便)


  • 锁子树

    • 局部性操纵

      • 优化性能(必要更美满的逻辑)


对停当队列加锁(自旋锁)



  • 队列操纵比较简朴,等待一些时间比直接睡眠线程更高效点
ET和LT

LT(Level Triggered,电平触发)



  • 默认,会重复提醒
ET(Edge Triggered,边沿触发)



  • 高效,必要手动设置,只提醒一次

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宝塔山

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表