【问题标题】:Can a thread be pre-empted in the midst of a system call to kernel?可以在系统调用内核的过程中抢占线程吗?
【发布时间】:2009-12-12 02:57:27
【问题描述】:

我正在运行 2 个线程(暂时假设它们是 pthreads)。 Thread_1() 进行用户定义的 API 调用,最终在内核中完成一些工作。 Thread_2() 完全在用户空间中。

我的问题是: Thread_2() 是否可以在 API 调用正在进行时通过抢占 Thread_1() 来开始执行,控制在内核内部的某个地方吗?如果不是,为什么,如果我希望这种情况发生(出于任何原因),我该怎么办?

【问题讨论】:

    标签: c++ c multithreading pthreads


    【解决方案1】:

    对内核的调用被认为是阻塞非阻塞。阻塞调用(例如等待从网络套接字读取数据)当然可以被抢占,而您不需要任何操作。其他线程将继续运行。非阻塞内核调用可以被认为是非常快的,实际上,您是否可以实际抢占它们并不重要。

    通常,在编写多线程代码时,您会专注于这些线程如何相互交互,并将它们与内核的交互留给内核来管理。它旨在做得很好。

    【讨论】:

    • 好吧,在这种情况下,我正在为 API 编写一个测试,测试计划涉及分析出现硬件中断时会发生什么(可以在用户中从 Thread_2() 启动)空间)在 API 的执行过程中。所以,理想情况下,我希望 Thread_1(_ 能够在 API 执行过程中让步,将控制权交给 Thread_2() (启动一个会导致硬件中断的序列),回到 Thread_1() 并恢复执行 - 如果 API 可以在硬件中断实际命中它时保持其自己/保存状态等,那么一切都很好!
    • 您可能想看看我在stackoverflow.com/questions/1885903/… 中考虑的替代方法。你可以跳过它——所有信息都在这个问题中! :)
    【解决方案2】:

    这取决于内核。经典的内核不允许抢占(除非在特定点睡眠线程)。但较新的内核已开始在内核本身内启用抢占。

    Linux 在使用 CONFIG_PREEMPT 构建时支持抢占式内核。来自内核文档:

    此选项通过使 所有内核代码(不在关键部分执行) 可抢占的。这允许通过以下方式对交互事件做出反应 允许不由自主地抢占低优先级进程 即使它在内核模式下执行系统调用并且会 否则不会达到自然抢占点。 这允许应用程序运行更“流畅”,即使在 系统处于负载状态,代价是吞吐量略低 并且内核代码的运行时开销很小。

    如果您正在为桌面构建内核或 具有毫秒级延迟要求的嵌入式系统 范围。

    【讨论】:

      【解决方案3】:

      如果您询问是否可以抢占像 fread() 这样需要磁盘 IO 的阻塞内核调用,那么可以。

      更具体地说,阻塞调用基本上会使 Thread_1 在等待它所等待的任何内容时进入睡眠状态。如果 Thread_1 处于休眠状态,则 Thread_2 将被安排运行(除非有更高优先级的东西等待运行)。

      编辑:如果您想要一种“相当有把握”地确定 Thread_1 正在执行阻塞调用的方法,请将 Thread_2 的优先级设置为低于 Thread_1(这样它通常不会 em> 运行,除非 Thread_1 被阻塞)并且当它运行时,它会将其优先级提升到比 Thread_1 更高的级别,直到交付硬件中断,此时它会降低其优先级并调用sched_yield()

      【讨论】:

      • 实际上这假设您的线程是内核管理的。有些内核可能会有所不同。
      • 你能澄清一下 - 内核管理和非内核管理之间的区别吗?存在哪些变化?
      • 非内核管理的线程被内核视为单个进程。该进程在内部(没有内核支持)调度其各种线程。通常,如果这些线程之一阻塞,则整个进程被内核视为阻塞,因此没有线程运行。如果线程是内核管理的,那么如果一个线程阻塞,大​​多数内核将运行其他线程。您可以运行一个简单的测试,其中一个线程重复调用系统调用,而另一个线程重复产生。如果屈服线程获得任何运行时,则意味着系统调用是一个抢占点。
      • 是否有可以调用的 API 来确定创建了哪种线程 - 托管/非托管?
      • 这只是您的操作系统和线程库的一个属性。桌面/服务器操作系统支持内核管理的线程,而一些嵌入式操作系统不支持,因为用户管理的线程开销较小。
      猜你喜欢
      • 2012-01-17
      • 1970-01-01
      • 2021-05-11
      • 1970-01-01
      • 2015-10-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      • 1970-01-01
      相关资源
      最近更新 更多