草庐IT

Linux 进程状态

coder 2023-04-29 原文

在 Linux 中,当进程需要从磁盘读取 block 时,它的状态会发生什么变化?被封锁了吗?如果是,如何选择另一个进程来执行?

最佳答案

当一个进程需要从磁盘获取数据时,它实际上会停止在 CPU 上运行以让其他进程运行,因为该操作可能需要很长时间才能完成——磁盘至少 5 毫秒的寻道时间是常见的,而 5 毫秒是 1000 万个 CPU 周期,从程序的角度来看是永恒的!

从程序员的角度来看(也称为“在用户空间中”),这称为阻塞系统调用。如果您调用 write(2)(它是同名系统调用的一个精简的 libc 包装器),您的进程不会完全停止在该边界处;它继续在内核中运行系统调用代码。大多数情况下,它一直到特定的磁盘 Controller 驱动程序(文件名→文件系统/VFS→ block 设备→设备驱动程序),其中获取磁盘上的 block 的命令被提交给适当的硬件,这是一个非常大部分时间运行速度很快。

然后进程进入 sleep 状态(在内核空间中,阻塞被称为 sleep ——从内核的角度来看,没有任何东西被“阻塞”过)。一旦硬件最终获取了正确的数据,它将被唤醒,然后该进程将被标记为可运行并被调度。最终,调度程序将运行该进程。

最后,在用户空间中,阻塞系统调用返回正确的状态和数据,程序流程继续进行。

可以在非阻塞模式中调用大多数 I/O 系统调用(参见 open(2) 中的 O_NONBLOCKfcntl(2))。在这种情况下,系统调用立即返回并且只报告提交磁盘操作。程序员稍后必须明确检查操作是否完成,成功与否,并获取其结果(例如,使用 select(2))。这称为异步或基于事件的编程。

这里提到 D 状态(在 Linux 状态名称中称为 TASK_UNINTERRUPTIBLE)的大多数答案都不正确。 D 状态是一种特殊的 sleep 模式,它只在内核空间代码路径中触发,当该代码路径不能被中断时(因为它太复杂了程序),期望它只会阻塞很短的时间。我相信大多数“D 状态”实际上是不可见的;它们的生命周期很短,无法通过“top”等采样工具观察到。

在少数情况下,您可能会遇到处于 D 状态的无法杀死的进程。 NFS 以它而闻名,我遇到过很多次。我认为一些 VFS 代码路径之间存在语义冲突,它假定总是到达本地磁盘和快速错误检测(在 SATA 上,错误超时大约为 100 毫秒)和 NFS,它实际上从网络获取数据更具弹性并且恢复缓慢(300 秒的 TCP 超时很常见)。阅读 this article对于 Linux 2.6.25 中引入的具有 TASK_KILLABLE 状态的酷解决方案。在这个时代之前,有一个黑客可以通过向内核线程 rpciod 发送 SIGKILL 来实际向 NFS 进程客户端发送信号,但忘记那个丑陋的技巧......

关于Linux 进程状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1475683/

有关Linux 进程状态的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  3. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  4. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  5. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  6. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  7. ruby-on-rails - 为模型创建状态属性 - 2

    我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,

  8. ruby - 无法在 Ruby 中将 ffmpeg 作为子进程运行 - 2

    我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope

  9. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  10. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

随机推荐