草庐IT

linux - 没有 epoll_waiting 时是否正在监视 epoll 事件

coder 2023-06-20 原文

我对基于事件的编程相当陌生。我正在试验 epolledge-mode,它显然只指示已准备好读/写的文件(与指示所有就绪文件的级别模式相反,无论是否已经准备就绪,或者刚刚准备就绪)。

我不清楚的是:在边缘模式下,我是否被告知在我未epoll_waiting 时发生的就绪事件?尚未重新装备的一次性文件上的事件如何处理?

为了说明我为什么这么问,请考虑以下场景:

  • 连接了 10 个非阻塞套接字
  • 配置 epoll_ctl 在套接字准备好读取时使用react,在 edge-mode + oneshot 中:EPOLLET | EPOLLONESHOT |埃波林
  • epoll_wait 等待某事发生(最多报告 10 个事件)
  • linux 唤醒我的进程并报告套接字 #1 和 #2 已准备就绪
  • 读取并处理数据套接字#1(直到E_AGAIN)
  • 读取并处理数据套接字#2(直到E_AGAIN)
  • 当我这样做的时候,套接字S接收数据
  • 我处理了所有事件,所以我在 EPOLL_CTL_MOD 模式下用 epoll_ctl 重新准备触发的文件,因为 oneshot
  • 我的循环返回到epoll_wait处理下一批事件

好的,那么最后一个 epoll_wait 总是 会被通知 socket S 就绪了吗? S 为 #1 时的事件(即未重新武装)?

最佳答案

I'm experimenting with epoll's edge-mode which apparently only signals files which have become ready for read/write (as opposed to level-mode which signals all ready files, regardless of whether there were already ready, or just became ready)

首先让我们清楚地了解系统,您需要一个关于系统工作原理的准确心智模型。您对 epoll(7) 的看法并不准确。

边沿触发和电平触发之间的区别在于对事件的确切定义。前者为文件描述符上订阅的每个 Action 生成一个事件;一旦你消费了这个事件,它就消失了——即使你没有消费产生这样一个事件的所有数据。 OTOH,后者会一遍又一遍地生成相同的事件,直到您使用了生成该事件的所有数据。

这是一个将这些概念付诸实践的例子,公然从 man 7 epoll 中窃取:

  1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.

  2. A pipe writer writes 2 kB of data on the write side of the pipe.

  3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.

  4. The pipe reader reads 1 kB of data from rfd.

  5. A call to epoll_wait(2) is done.

If the rfd file descriptor has been added to the epoll interface using the EPOLLET (edge-triggered) flag, the call to epoll_wait(2) done in step 5 will probably hang despite the available data still present in the file input buffer; meanwhile the remote peer might be expecting a response based on the data it already sent. The reason for this is that edge-triggered mode delivers events only when changes occur on the monitored file descriptor. So, in step 5 the caller might end up waiting for some data that is already present inside the input buffer. In the above example, an event on rfd will be generated because of the write done in 2 and the event is consumed in 3. Since the read operation done in 4 does not consume the whole buffer data, the call to epoll_wait(2) done in step 5 might block indefinitely.

简而言之,根本区别在于“事件”的定义:边缘触发将事件视为您消耗一次的单个单元; level-triggered 将事件的消耗定义为等同于消耗属于该事件的所有数据。

现在,让我们解决您的具体问题。

in edge-mode, am I informed of readiness events that happen while I'm not epoll_waiting

是的,你是。在内部,内核将每个文件描述符上发生的有趣事件排队。它们会在下次调用 epoll_wait(2) 时返回,因此您可以放心不会丢失事件。好吧,如果还有其他事件未决并且传递给 epoll_wait(2) 的事件缓冲区不能容纳所有事件,那么可能不会在下一次调用时发生,但关键是,最终这些事件将被报告.

What about events on one-shot files that haven't been rearmed yet?

同样,您永远不会丢失事件。如果文件描述符还没有重新装备,如果出现任何有趣的事件,它只是在内存中排队,直到文件描述符重新装备。一旦它重新装备,任何未决事件——包括那些在描述符被重新装备之前发生的事件——将在下一次调用 epoll_wait(2) 时报告(同样,可能不会恰好是下一个,但它们会被报告)。换句话说,EPOLLONESHOT 不会禁用事件监视,它只是暂时禁用事件通知

Ok, so will the last epoll_wait always be notified of the readiness of socket S? Event if S is #1 (i.e. it's not rearmed)?

鉴于我上面所说的,现在应该很清楚了:是的,它会的。您不会丢失任何事件。 epoll 提供了强有力的保证,它很棒。它也是线程安全的,您可以在不同线程中等待同一个 epoll fd 并同时更新事件订阅。 epoll非常强大,值得花时间学习!

关于linux - 没有 epoll_waiting 时是否正在监视 epoll 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31581918/

有关linux - 没有 epoll_waiting 时是否正在监视 epoll 事件的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  3. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  4. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  7. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  8. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

  9. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  10. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

随机推荐