<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>内核 on Tech Snippets - 嵌入式技术笔记</title><link>https://tech-snippets.xyz/tags/%E5%86%85%E6%A0%B8/</link><description>Recent content in 内核 on Tech Snippets - 嵌入式技术笔记</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 12 May 2026 19:00:00 +0800</lastBuildDate><atom:link href="https://tech-snippets.xyz/tags/%E5%86%85%E6%A0%B8/index.xml" rel="self" type="application/rss+xml"/><item><title>嵌入式 Linux 实时性优化与 PREEMPT_RT 补丁实战指南</title><link>https://tech-snippets.xyz/posts/linux-preempt-rt-real-time-optimization-guide/</link><pubDate>Tue, 12 May 2026 19:00:00 +0800</pubDate><guid>https://tech-snippets.xyz/posts/linux-preempt-rt-real-time-optimization-guide/</guid><description>前言 在工业控制、机器人、汽车电子等领域，确定性比平均性能更加重要。一个控制系统如果不能在规定的时间窗口内完成响应，即使平均响应时间再短，也可能导致灾难性的后果——生产线停摆、机器人失控、汽车 ADAS 失效。
传统的 Linux 内核虽然在吞吐量和平均延迟方面表现出色，但在最坏情况延迟（Worst-Case Latency）方面却不尽人意。在高负载情况下，普通 Linux 内核的调度延迟可能达到数十毫秒甚至数百毫秒级别，这对于要求微秒级确定性的实时应用来说是完全不可接受的。
这就是 PREEMPT_RT 补丁存在的意义。
PREEMPT_RT（Real-Time Preemption Patch）是一组针对 Linux 内核的补丁集，其目标是将 Linux 内核改造为一个完全可抢占的实时操作系统。经过二十多年的发展，PREEMPT_RT 已经从一个实验性项目成长为工业级实时解决方案的事实标准，大量关键代码甚至已经合入主线内核。
本文将从实时系统的基本概念出发，深入解析 PREEMPT_RT 的核心原理，带你从零开始打补丁、编译实时内核、配置系统、进行延迟测试，最终构建一个真正满足工业级要求的实时 Linux 系统。
一、什么是真正的实时系统？ 在深入 PREEMPT_RT 之前，我们首先需要澄清一个普遍的误解：快 ≠ 实时。
很多开发者一听到&amp;quot;实时系统&amp;quot;，第一反应就是&amp;quot;运行很快的系统&amp;quot;。这是一个根本性的错误认知。
1.1 实时性的本质：确定性 实时系统的核心特征不是&amp;quot;快&amp;quot;，而是可预测性或确定性。系统必须能够保证：关键任务在截止时间之前完成。
让我们通过一个具体的例子来说明：
假设我们有一个工业机器人的运动控制系统，要求每 1 毫秒执行一次位置控制循环。如果控制系统的响应时间分布如下：
系统 A：平均响应 500 微秒，最坏情况 1.5 毫秒（偶尔超时） 系统 B：平均响应 800 微秒，最坏情况 950 微秒（从不超时） 哪个系统是&amp;quot;实时&amp;quot;的？
答案是 系统 B。尽管它的平均响应更慢，但它的最坏情况延迟始终小于截止时间，具有完美的确定性。而系统 A 虽然更快，但偶尔会超时，在实际工业场景中这可能导致机器人运动轨迹偏差、甚至发生碰撞。
1.2 实时系统的分类 根据对截止时间的要求严格程度，实时系统可以分为三类：
硬实时（Hard Real-Time）
绝对不能错过截止时间 错过 = 系统失败 典型场景：航空电子、汽车安全系统、工业控制 PREEMPT_RT 目标：在合理配置下达到硬实时级别 软实时（Soft Real-Time）</description><content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>在工业控制、机器人、汽车电子等领域，<strong>确定性</strong>比<strong>平均性能</strong>更加重要。一个控制系统如果不能在规定的时间窗口内完成响应，即使平均响应时间再短，也可能导致灾难性的后果——生产线停摆、机器人失控、汽车 ADAS 失效。</p>
<p>传统的 Linux 内核虽然在吞吐量和平均延迟方面表现出色，但在最坏情况延迟（Worst-Case Latency）方面却不尽人意。在高负载情况下，普通 Linux 内核的调度延迟可能达到数十毫秒甚至数百毫秒级别，这对于要求微秒级确定性的实时应用来说是完全不可接受的。</p>
<p>这就是 PREEMPT_RT 补丁存在的意义。</p>
<p>PREEMPT_RT（Real-Time Preemption Patch）是一组针对 Linux 内核的补丁集，其目标是将 Linux 内核改造为一个完全可抢占的实时操作系统。经过二十多年的发展，PREEMPT_RT 已经从一个实验性项目成长为工业级实时解决方案的事实标准，大量关键代码甚至已经合入主线内核。</p>
<p>本文将从实时系统的基本概念出发，深入解析 PREEMPT_RT 的核心原理，带你从零开始打补丁、编译实时内核、配置系统、进行延迟测试，最终构建一个真正满足工业级要求的实时 Linux 系统。</p>
<h2 id="一什么是真正的实时系统">一、什么是真正的实时系统？</h2>
<p>在深入 PREEMPT_RT 之前，我们首先需要澄清一个普遍的误解：<strong>快 ≠ 实时</strong>。</p>
<p>很多开发者一听到&quot;实时系统&quot;，第一反应就是&quot;运行很快的系统&quot;。这是一个根本性的错误认知。</p>
<h3 id="11-实时性的本质确定性">1.1 实时性的本质：确定性</h3>
<p>实时系统的核心特征不是&quot;快&quot;，而是<strong>可预测性</strong>或<strong>确定性</strong>。系统必须能够保证：<strong>关键任务在截止时间之前完成</strong>。</p>
<p>让我们通过一个具体的例子来说明：</p>
<p>假设我们有一个工业机器人的运动控制系统，要求每 1 毫秒执行一次位置控制循环。如果控制系统的响应时间分布如下：</p>
<ul>
<li>系统 A：平均响应 500 微秒，最坏情况 1.5 毫秒（偶尔超时）</li>
<li>系统 B：平均响应 800 微秒，最坏情况 950 微秒（从不超时）</li>
</ul>
<p>哪个系统是&quot;实时&quot;的？</p>
<p>答案是 <strong>系统 B</strong>。尽管它的平均响应更慢，但它的最坏情况延迟始终小于截止时间，具有完美的确定性。而系统 A 虽然更快，但偶尔会超时，在实际工业场景中这可能导致机器人运动轨迹偏差、甚至发生碰撞。</p>
<h3 id="12-实时系统的分类">1.2 实时系统的分类</h3>
<p>根据对截止时间的要求严格程度，实时系统可以分为三类：</p>
<p><strong>硬实时（Hard Real-Time）</strong></p>
<ul>
<li>绝对不能错过截止时间</li>
<li>错过 = 系统失败</li>
<li>典型场景：航空电子、汽车安全系统、工业控制</li>
<li>PREEMPT_RT 目标：在合理配置下达到硬实时级别</li>
</ul>
<p><strong>软实时（Soft Real-Time）</strong></p>
<ul>
<li>尽量满足截止时间</li>
<li>错过会降低服务质量，但不会导致系统失败</li>
<li>典型场景：视频流媒体、VoIP、桌面交互</li>
</ul>
<p>** firm 实时**</p>
<ul>
<li>截止时间错过后，结果失去价值</li>
<li>典型场景：股票交易系统、传感器数据采集</li>
</ul>
<h3 id="13-linux-为什么需要-preempt_rt">1.3 Linux 为什么需要 PREEMPT_RT？</h3>
<p>标准 Linux 内核从设计之初就不是为实时系统准备的。它的设计目标是最大化<strong>吞吐量</strong>，而不是最小化<strong>最坏情况延迟</strong>。</p>
<p>为了理解这个问题，我们需要看看内核中的不可抢占区域：</p>
<pre tabindex="0"><code>中断上下文 → 自旋锁持有 → 抢占禁用
    ↓            ↓            ↓
┌───────────────────────────────────┐
│      内核不可抢占窗口             │
│  在此期间，高优先级任务无法运行  │
└───────────────────────────────────┘
            ↓
    最坏情况延迟增加
</code></pre><p>在标准内核中，以下情况会导致抢占被禁用：</p>
<ol>
<li><strong>持有自旋锁（Spinlock）</strong>：传统自旋锁持有期间抢占被禁用</li>
<li><strong>中断上下文执行</strong>：中断处理程序执行时无法被抢占</li>
<li><strong>显式禁用抢占</strong>：代码中调用 <code>preempt_disable()</code></li>
<li><strong>RCU 读侧临界区</strong>：传统 RCU 读期间抢占被禁用</li>
</ol>
<p>这些不可抢占窗口就是造成延迟抖动的主要原因。在极端情况下，某些驱动程序的中断处理程序可能执行数毫秒，期间所有用户空间任务都无法运行——这对于硬实时系统来说是不可接受的。</p>
<p>PREEMPT_RT 的核心目标就是：<strong>消除这些不可抢占窗口，让内核变得几乎完全可抢占</strong>。</p>
<h2 id="二preempt_rt-核心原理深度解析">二、PREEMPT_RT 核心原理深度解析</h2>
<p>PREEMPT_RT 并不是一个单一的补丁，而是由数十个独立的补丁组成的补丁集。每个补丁解决一个特定的抢占问题，它们协同工作，最终实现完整的内核抢占能力。</p>
<h3 id="21-自旋锁改造sleeping-spinlocks">2.1 自旋锁改造：Sleeping Spinlocks</h3>
<p>标准内核中的自旋锁是不可抢占的。当一个 CPU 持有自旋锁时，该 CPU 上的抢占会被完全禁用。如果持有自旋锁的代码执行时间很长，就会造成很长的不可抢占窗口。</p>
<p>PREEMPT_RT 对自旋锁进行了根本性的改造：</p>
<p><strong>改造前（标准内核）：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">spin_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span><span class="p">);</span>        <span class="c1">// 禁用抢占 + 忙等待
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">critical_section</span><span class="p">();</span>      <span class="c1">// 不可抢占
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">spin_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span><span class="p">);</span>      <span class="c1">// 恢复抢占
</span></span></span></code></pre></div><p><strong>改造后（PREEMPT_RT）：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">rt_spin_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span><span class="p">);</span>     <span class="c1">// 启用抢占 + 阻塞等待
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">critical_section</span><span class="p">();</span>      <span class="c1">// 可被抢占！
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_spin_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">lock</span><span class="p">);</span>
</span></span></code></pre></div><p>关键区别在于：在 PREEMPT_RT 中，自旋锁被替换成了<strong>可睡眠的 rt_mutex</strong>。当锁被占用时，等待任务不会忙等，而是会阻塞睡眠。更重要的是，<strong>持有锁的临界区本身是可以被抢占的</strong>！</p>
<p>这意味着即使某个任务持有自旋锁在执行，高优先级的实时任务仍然可以抢占它。这是 PREEMPT_RT 最重要的设计之一。</p>
<p>当然，这种改造也带来了新的问题：如果持有锁的低优先级任务被高优先级任务抢占，而高优先级任务又试图获取同一个锁，就会形成优先级反转。为了解决这个问题，PREEMPT_RT 实现了完整的**优先级继承（Priority Inheritance）**机制。</p>
<h3 id="22-中断线程化threaded-interrupts">2.2 中断线程化：Threaded Interrupts</h3>
<p>标准内核中，中断处理程序（ISR）运行在中断上下文，具有最高的执行优先级，无法被任何任务抢占。如果某个驱动的 ISR 执行时间很长，就会阻塞所有其他任务。</p>
<p>PREEMPT_RT 的解决方案是：<strong>将几乎所有中断处理程序线程化</strong>。</p>
<p><img alt="PREEMPT_RT 中断线程化架构" loading="lazy" src="/images/preempt-rt-interrupt-threading.svg"></p>
<p>如图所示，在 PREEMPT_RT 内核中：</p>
<ol>
<li>硬件中断触发后，只执行一个最小的&quot;前言&quot;处理</li>
<li>然后唤醒对应的中断处理线程</li>
<li>实际的中断处理工作在线程上下文中执行</li>
<li>中断线程是可调度、可抢占的！</li>
</ol>
<p>这样一来，中断处理就变成了一个普通的内核线程，可以被更高优先级的实时任务抢占。你甚至可以通过 <code>chrt</code> 命令调整各个中断线程的优先级，根据实际需求对中断进行优先级排序。</p>
<p>你可以通过以下命令查看中断线程：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ps -eLf <span class="p">|</span> grep <span class="s2">&#34;\[irq&#34;</span>
</span></span></code></pre></div><p>典型输出：</p>
<pre tabindex="0"><code>root        62     2  0 19:00 ?        00:00:00 [irq/9-acpi]
root        73     2  0 19:00 ?        00:00:00 [irq/16-uhci_hcd]
root        74     2  0 19:00 ?        00:00:00 [irq/17-eth0]
root        75     2  0 19:00 ?        00:00:00 [irq/18-snd_hda]
</code></pre><p>这些 <code>[irq/xx-xxx]</code> 进程就是中断处理线程，它们的默认优先级是 50（SCHED_FIFO）。</p>
<h3 id="23-高分辨率定时器hrtimers">2.3 高分辨率定时器：hrtimers</h3>
<p>标准内核的定时器基于 tick 机制，通常是 100Hz 或 1000Hz，对应的粒度是 10ms 或 1ms。这意味着你无法获得比 tick 粒度更精确的定时。</p>
<p>PREEMPT_RT 充分利用了硬件提供的高分辨率定时器（hrtimers），可以达到微秒级甚至纳秒级的定时精度。</p>
<p>hrtimers 的核心改进：</p>
<ul>
<li><strong>时间表示</strong>：使用 <code>ktime_t</code> 类型，64 位纳秒精度</li>
<li><strong>组织方式</strong>：红黑树组织，按超时时间排序，而不是传统的定时器轮</li>
<li><strong>精度保证</strong>：只要硬件支持，就能达到真正的微秒级精度</li>
</ul>
<p>这对于需要精确周期执行的实时控制任务至关重要。例如，一个 1kHz 的控制回路要求每 1000 微秒精确唤醒一次，这只有 hrtimers 才能可靠实现。</p>
<h3 id="24-其他关键改造">2.4 其他关键改造</h3>
<p>除了上述三大核心机制外，PREEMPT_RT 还包含了大量其他改进：</p>
<p><strong>RCU 可抢占化</strong></p>
<ul>
<li>标准 RCU 读侧临界区不可抢占</li>
<li>PREEMPT_RT 实现了可抢占 RCU（CONFIG_PREEMPT_RCU）</li>
<li>RCU 读期间可以被高优先级任务抢占</li>
</ul>
<p><strong>内存分配改进</strong></p>
<ul>
<li><code>GFP_ATOMIC</code> 分配限制在合理范围内</li>
<li>实时安全的内存分配路径</li>
<li>页面回收机制优化，避免长时间阻塞</li>
</ul>
<p><strong>锁粒度细化</strong></p>
<ul>
<li>对核心内核锁进行更细粒度的拆分</li>
<li>减少大内核锁（BKL）的影响范围（BKL 现已完全移除）</li>
</ul>
<p>（第一部分完，约 2300 字）</p>
<h2 id="三preempt_rt-内核编译实战">三、PREEMPT_RT 内核编译实战</h2>
<p>理论讲解之后，让我们进入实战环节。从零开始编译一个带有 PREEMPT_RT 补丁的实时内核。</p>
<h3 id="31-准备工作环境">3.1 准备工作环境</h3>
<p>首先，我们需要安装必要的编译依赖：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Debian/Ubuntu 系列</span>
</span></span><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">sudo apt install -y build-essential libncurses-dev bison flex <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    libssl-dev libelf-dev bc git wget cpio unzip rsync <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    python3-pip pahole dwarves
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># RHEL/CentOS 系列</span>
</span></span><span class="line"><span class="cl">sudo dnf groupinstall <span class="s2">&#34;Development Tools&#34;</span>
</span></span><span class="line"><span class="cl">sudo dnf install ncurses-devel bison flex openssl-devel <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    elfutils-libelf-devel bc dwarves
</span></span></code></pre></div><h3 id="32-下载内核源码与补丁">3.2 下载内核源码与补丁</h3>
<p>PREEMPT_RT 补丁的官方发布地址是：
<a href="https://cdn.kernel.org/pub/linux/kernel/projects/rt/">https://cdn.kernel.org/pub/linux/kernel/projects/rt/</a></p>
<p>选择补丁版本时需要注意：<strong>补丁版本必须与内核源码版本精确匹配</strong>。例如，patch-5.15.100-rt62.patch 只能应用于 linux-5.15.100.tar.xz。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 创建工作目录</span>
</span></span><span class="line"><span class="cl">mkdir -p ~/rt-kernel <span class="o">&amp;&amp;</span> <span class="nb">cd</span> ~/rt-kernel
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 选择内核版本（以 5.15 长期支持版为例）</span>
</span></span><span class="line"><span class="cl"><span class="nv">KERNEL_VERSION</span><span class="o">=</span><span class="s2">&#34;5.15.100&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">RT_VERSION</span><span class="o">=</span><span class="s2">&#34;rt62&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载内核源码</span>
</span></span><span class="line"><span class="cl">wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>.tar.xz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 PREEMPT_RT 补丁</span>
</span></span><span class="line"><span class="cl">wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.15/patch-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>-<span class="si">${</span><span class="nv">RT_VERSION</span><span class="si">}</span>.patch.xz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 解压</span>
</span></span><span class="line"><span class="cl">tar xf linux-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>.tar.xz
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> linux-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>
</span></span></code></pre></div><h3 id="33-应用补丁">3.3 应用补丁</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 解压并应用补丁</span>
</span></span><span class="line"><span class="cl">xzcat ../patch-<span class="si">${</span><span class="nv">KERNEL_VERSION</span><span class="si">}</span>-<span class="si">${</span><span class="nv">RT_VERSION</span><span class="si">}</span>.patch.xz <span class="p">|</span> patch -p1
</span></span></code></pre></div><p>如果补丁应用成功，你会看到大量的 <code>patching file xxx</code> 输出，没有任何 <code>FAILED</code> 消息。</p>
<p><strong>💡 提示：</strong> 从 Linux 6.6 开始，大量 PREEMPT_RT 代码已经合入主线。你只需要在配置中启用 <code>CONFIG_PREEMPT_RT</code> 即可，不再需要打额外的补丁！这是 PREEMPT_RT 发展历程中的重要里程碑。</p>
<h3 id="34-内核配置">3.4 内核配置</h3>
<p>这是最关键的一步。正确的配置决定了最终的实时性能。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 使用当前系统配置作为基础</span>
</span></span><span class="line"><span class="cl">cp /boot/config-<span class="k">$(</span>uname -r<span class="k">)</span> .config
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 启动菜单配置</span>
</span></span><span class="line"><span class="cl">make menuconfig
</span></span></code></pre></div><p>按照以下路径设置关键选项：</p>
<pre tabindex="0"><code># 1. 启用完全实时抢占（最重要！）
General setup → Preemption Model
  (X) Fully Preemptible Kernel (Real-Time)
  # 选项对应 CONFIG_PREEMPT_RT=y

# 2. 高分辨率定时器支持
General setup Timers subsystem → High Resolution Timer Support
  [*] High Resolution Timer Support
  # CONFIG_HIGH_RES_TIMERS=y

# 3. 中断线程化
General setup → Timers subsystem
  [*] Threaded interrupts handling forced by default
  # CONFIG_FORCE_THREAD_IRQS=y

# 4. RCU 配置
Kernel hacking → RCU Debugging
  [ ] Force consistent RCU tracing state  # 关闭！会增加延迟
  # CONFIG_RCU_TRACE=n

# 5. 关闭调试功能（非常重要！）
Kernel hacking
  [ ] KGDB: kernel debugger
  [ ] Kprobes
  [ ] Lock Debugging
  # 所有调试选项都应该关闭！它们会严重影响延迟

# 6. CPU Frequency 配置
Power management and ACPI options → CPU Frequency scaling
  [ ] CPU Frequency scaling  # 或者
  Default CPUFreq governor (performance)
  # 使用 performance  governor 获得最佳实时性

# 7. 关闭电源管理
Power management and ACPI options
  [ ] Suspend to RAM and standby
  [ ] Hibernation
  CPU Idle → CPU idle PM support → [ ]  # 建议关闭

# 8. 透明巨页
Memory Management options
  [ ] Transparent Hugepage Support
  # THP 会造成不可预测的延迟，建议关闭
</code></pre><h3 id="35-编译与安装">3.5 编译与安装</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 编译（使用所有 CPU 核心）</span>
</span></span><span class="line"><span class="cl">make -j<span class="k">$(</span>nproc<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 安装模块</span>
</span></span><span class="line"><span class="cl">sudo make modules_install
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 安装内核</span>
</span></span><span class="line"><span class="cl">sudo make install
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 更新 grub</span>
</span></span><span class="line"><span class="cl">sudo update-grub
</span></span></code></pre></div><p>编译时间取决于你的 CPU 性能，通常需要 30 分钟到 2 小时不等。</p>
<h3 id="36-验证实时内核">3.6 验证实时内核</h3>
<p>重启并选择新内核启动后，验证实时性：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 检查内核版本（应该含有 -rt 标记）</span>
</span></span><span class="line"><span class="cl">uname -a
</span></span><span class="line"><span class="cl"><span class="c1"># 输出示例：Linux 5.15.100-rt62 #1 SMP PREEMPT_RT ...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 检查抢占模型</span>
</span></span><span class="line"><span class="cl">cat /sys/kernel/realtime
</span></span><span class="line"><span class="cl"><span class="c1"># 输出: 1  → 实时内核已启用</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 检查中断线程</span>
</span></span><span class="line"><span class="cl">ps -eLf <span class="p">|</span> grep <span class="s2">&#34;\[irq&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 检查高分辨率定时器</span>
</span></span><span class="line"><span class="cl">cat /proc/timer_list <span class="p">|</span> grep resolution
</span></span><span class="line"><span class="cl"><span class="c1"># 输出: .resolution: 1 nsecs</span>
</span></span></code></pre></div><p>如果看到 <code>PREEMPT_RT</code> 标记和 <code>realtime: 1</code>，恭喜你，实时内核已经成功运行！</p>
<h2 id="四系统实时性调优指南">四、系统实时性调优指南</h2>
<p>仅仅安装实时内核是不够的。要达到最佳的实时性能，还需要对整个系统进行精细调优。</p>
<h3 id="41-内核启动参数优化">4.1 内核启动参数优化</h3>
<p>编辑 <code>/etc/default/grub</code>，添加以下参数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">GRUB_CMDLINE_LINUX_DEFAULT</span><span class="o">=</span><span class="s2">&#34;quiet splash \
</span></span></span><span class="line"><span class="cl"><span class="s2">    isolcpus=2-3 \          # 隔离 CPU 2,3 供实时任务专用
</span></span></span><span class="line"><span class="cl"><span class="s2">    nohz_full=2-3 \         # 这些 CPU 进入完全无 tick 模式
</span></span></span><span class="line"><span class="cl"><span class="s2">    rcu_nocbs=2-3 \         # RCU 回调不调度到这些 CPU
</span></span></span><span class="line"><span class="cl"><span class="s2">    irqaffinity=0-1 \       # 中断只路由到 CPU 0,1
</span></span></span><span class="line"><span class="cl"><span class="s2">    processor.max_cstate=1 \# 限制 C-state，减少唤醒延迟
</span></span></span><span class="line"><span class="cl"><span class="s2">    intel_idle.max_cstate=0 \
</span></span></span><span class="line"><span class="cl"><span class="s2">    idle=poll \             # 忙等待 idle，消除 idle 唤醒延迟
</span></span></span><span class="line"><span class="cl"><span class="s2">    transparent_hugepage=never \
</span></span></span><span class="line"><span class="cl"><span class="s2">    skew_tick=1&#34;</span>
</span></span></code></pre></div><p>然后更新 grub：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo update-grub
</span></span></code></pre></div><p><strong>参数详解：</strong></p>
<ul>
<li><strong>isolcpus</strong>：从内核调度器中隔离指定 CPU，只有明确绑定的任务才能运行在这些 CPU 上。这是获得确定性的最有效手段之一。</li>
<li><strong>nohz_full</strong>：完全禁用指定 CPU 的周期 tick。通常情况下，内核每 1ms（或 10ms）会产生一个 tick 来进行统计和调度，这会打断正在运行的实时任务。</li>
<li><strong>rcu_nocbs</strong>：将 RCU 回调处理 offload 到其他 CPU，避免 RCU 操作干扰实时 CPU。</li>
<li><strong>idle=poll</strong>：CPU 空闲时不进入低功耗状态，而是忙等。这会增加功耗，但可以将唤醒延迟从数十微秒降低到 1-2 微秒。</li>
</ul>
<h3 id="42-中断亲和性配置">4.2 中断亲和性配置</h3>
<p>默认情况下，中断可能会路由到任何 CPU。我们需要确保中断不会打扰隔离的实时 CPU：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看当前中断亲和性</span>
</span></span><span class="line"><span class="cl">cat /proc/irq/17/smp_affinity_list
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置 eth0 中断只在 CPU 0 上处理</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="m">0</span> &gt; /proc/irq/17/smp_affinity_list
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 脚本：将所有中断绑定到非实时 CPU</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> irq in <span class="k">$(</span>ls /proc/irq <span class="p">|</span> grep -E <span class="s1">&#39;^[0-9]+$&#39;</span><span class="k">)</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> 0-1 &gt; /proc/irq/<span class="nv">$irq</span>/smp_affinity_list 2&gt;/dev/null
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span></code></pre></div><p>对于使用 <code>smp_affinity</code>（十六进制位图）的旧系统：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># CPU 0 = 0x01, CPU 1 = 0x02, CPU 0+1 = 0x03</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="m">03</span> &gt; /proc/irq/17/smp_affinity
</span></span></code></pre></div><h3 id="43-调度策略与优先级">4.3 调度策略与优先级</h3>
<p>Linux 提供了三种主要的调度策略：</p>
<table>
<thead>
<tr>
<th>调度策略</th>
<th>优先级范围</th>
<th>特点</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>SCHED_OTHER</td>
<td>0 (nice -20~19)</td>
<td>CFS 公平调度</td>
<td>普通任务</td>
</tr>
<tr>
<td>SCHED_RR</td>
<td>1-99</td>
<td>实时，时间片轮转</td>
<td>软实时任务</td>
</tr>
<tr>
<td>SCHED_FIFO</td>
<td>1-99</td>
<td>实时，先进先出</td>
<td>硬实时任务，可抢占其他所有任务</td>
</tr>
</tbody>
</table>
<p>设置实时任务优先级：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 以 SCHED_FIFO 优先级 80 启动程序</span>
</span></span><span class="line"><span class="cl">chrt -f <span class="m">80</span> ./my-realtime-app
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看当前调度策略</span>
</span></span><span class="line"><span class="cl">chrt -p <span class="nv">$$</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 动态修改运行中进程的优先级</span>
</span></span><span class="line"><span class="cl">chrt -f -p <span class="m">90</span> &lt;pid&gt;
</span></span></code></pre></div><p><strong>优先级选择建议：</strong></p>
<ul>
<li>中断线程默认优先级：50</li>
<li>普通实时任务：51-80</li>
<li>最关键的控制任务：81-99</li>
<li>不要使用 99，这会和内核 watchdog 等最高优先级任务冲突</li>
</ul>
<h3 id="44-内存锁定">4.4 内存锁定</h3>
<p>实时任务应该避免任何形式的页面交换。使用 <code>mlockall()</code> 锁定所有内存：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 在程序启动时调用
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="k">if</span> <span class="p">(</span><span class="nf">mlockall</span><span class="p">(</span><span class="n">MCL_CURRENT</span> <span class="o">|</span> <span class="n">MCL_FUTURE</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;mlockall failed&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>也可以通过 <code>ulimit</code> 设置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 允许锁定无限内存</span>
</span></span><span class="line"><span class="cl"><span class="nb">ulimit</span> -l unlimited
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 持久化配置（/etc/security/limits.conf）</span>
</span></span><span class="line"><span class="cl">@realtime      -    memlock    unlimited
</span></span><span class="line"><span class="cl">@realtime      -    rtprio     <span class="m">99</span>
</span></span></code></pre></div><p>（第二部分完，约 2400 字）</p>
<h2 id="五延迟测试与性能验证">五、延迟测试与性能验证</h2>
<p>调优完成后，必须通过客观的测试数据来验证实时性能是否真的达到了预期。</p>
<h3 id="51-使用-cyclictest-进行延迟基准测试">5.1 使用 cyclictest 进行延迟基准测试</h3>
<p><code>cyclictest</code> 是实时 Linux 社区公认的标准测试工具，来自 <code>rt-tests</code> 套件。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 安装 rt-tests</span>
</span></span><span class="line"><span class="cl">git clone git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> rt-tests
</span></span><span class="line"><span class="cl">make all
</span></span><span class="line"><span class="cl">sudo make install
</span></span></code></pre></div><p>执行标准延迟测试：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 基础测试（运行 1 小时）</span>
</span></span><span class="line"><span class="cl">sudo cyclictest -l1000000 -m -S -p90 -i200 -h400 -q &gt; latency.txt
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 参数说明：</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -l1000000  : 循环 100 万次</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -m         : mlockall 锁定内存</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -S         : 使用 SCHED_FIFO</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -p90       : 优先级 90</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -i200      : 测试间隔 200 微秒</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -h400      : 直方图，最大 400 微秒</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -q         : 安静模式，只输出最终结果</span>
</span></span></code></pre></div><p>典型输出分析：</p>
<pre tabindex="0"><code># /dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.52 0.31 0.18 1/123 12345          

T: 0 (12345) P:90 I:200 C: 1000000 Min: 1 Act: 2 Avg: 2 Max:  8
T: 1 (12346) P:90 I:200 C: 1000000 Min: 1 Act: 2 Avg: 2 Max:  9
T: 2 (12347) P:90 I:200 C: 1000000 Min: 1 Act: 2 Avg: 2 Max:  7
T: 3 (12348) P:90 I:200 C: 1000000 Min: 1 Act: 2 Avg: 2 Max:  6
</code></pre><p><strong>结果解读：</strong></p>
<ul>
<li><strong>Min</strong>: 最小延迟（微秒）</li>
<li><strong>Avg</strong>: 平均延迟（微秒）</li>
<li><strong>Max</strong>: 最坏情况延迟（微秒）← 这是最重要的指标！</li>
</ul>
<p><strong>延迟评价标准：</strong></p>
<table>
<thead>
<tr>
<th>Max 延迟</th>
<th>评价</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>&lt; 10 μs</td>
<td>优秀</td>
<td>工业控制、机器人</td>
</tr>
<tr>
<td>10-50 μs</td>
<td>良好</td>
<td>大多数实时应用</td>
</tr>
<tr>
<td>50-100 μs</td>
<td>一般</td>
<td>需要进一步调优</td>
</tr>
<tr>
<td>&gt; 100 μs</td>
<td>较差</td>
<td>配置有严重问题</td>
</tr>
</tbody>
</table>
<h3 id="52-压力测试下的延迟表现">5.2 压力测试下的延迟表现</h3>
<p>真实场景中系统不会是空闲的。需要在压力下测试：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 终端 1：产生 CPU 压力</span>
</span></span><span class="line"><span class="cl">stress-ng --cpu <span class="m">8</span> --io <span class="m">4</span> --vm <span class="m">2</span> --vm-bytes 128M
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 终端 2：产生网络压力</span>
</span></span><span class="line"><span class="cl">iperf3 -c &lt;server-ip&gt; -t <span class="m">3600</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 终端 3：运行 cyclictest</span>
</span></span><span class="line"><span class="cl">sudo cyclictest -m -S -p90 -D1h  <span class="c1"># 运行 1 小时</span>
</span></span></code></pre></div><p>一个配置良好的 PREEMPT_RT 系统，即使在满负载压力下，最坏延迟也应该能保持在 20 微秒以内。</p>
<h3 id="53-使用-ftrace-分析延迟来源">5.3 使用 ftrace 分析延迟来源</h3>
<p>如果延迟超标，可以使用 ftrace 定位问题：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 挂载 tracefs</span>
</span></span><span class="line"><span class="cl">sudo mount -t tracefs none /sys/kernel/tracing
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 启用延迟追踪</span>
</span></span><span class="line"><span class="cl">sudo <span class="nb">echo</span> <span class="m">1</span> &gt; /sys/kernel/tracing/events/irq/enable
</span></span><span class="line"><span class="cl">sudo <span class="nb">echo</span> <span class="m">1</span> &gt; /sys/kernel/tracing/events/sched/sched_switch/enable
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 运行 cyclictest 记录最大延迟</span>
</span></span><span class="line"><span class="cl">sudo cyclictest -b <span class="m">20</span> -f trace.dat  <span class="c1"># 延迟超过 20μs 时触发 trace</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 分析结果</span>
</span></span><span class="line"><span class="cl">sudo trace-cmd report
</span></span></code></pre></div><p>常见的延迟来源：</p>
<ul>
<li>某个驱动的中断处理时间过长</li>
<li>内核中有未被补丁覆盖的长临界区</li>
<li>BIOS/固件引起的 SMM 模式执行</li>
<li>PCIe 设备的错误恢复机制</li>
</ul>
<h2 id="六常见问题与解决方案">六、常见问题与解决方案</h2>
<h3 id="61-为什么我的延迟还是很差">6.1 为什么我的延迟还是很差？</h3>
<p>这是最常见的问题。按照以下步骤排查：</p>
<p><strong>第一步：检查内核配置</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 确认实时内核</span>
</span></span><span class="line"><span class="cl">grep PREEMPT_RT /boot/config-<span class="k">$(</span>uname -r<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 应该输出: CONFIG_PREEMPT_RT=y</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 确认没有启用调试</span>
</span></span><span class="line"><span class="cl">grep DEBUG /boot/config-<span class="k">$(</span>uname -r<span class="k">)</span> <span class="p">|</span> grep <span class="s2">&#34;=y&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 应该没有太多调试选项被启用</span>
</span></span></code></pre></div><p><strong>第二步：检查 BIOS 设置</strong></p>
<pre tabindex="0"><code>BIOS 中必须关闭：
- C-State （所有 C1 以上的状态）
- CPU 电源管理（SpeedStep、P-State）
- Intel Turbo Boost
- 超线程（Hyper-Threading）← 可选，但建议关闭
- VT-d / IOMMU ← 如果不需要可以关闭
</code></pre><p><strong>第三步：检查是否有 SMM 干扰</strong></p>
<p>系统管理模式（SMM）是 BIOS 执行的最高特权代码，完全不可被操作系统控制，会造成 50-500 微秒的延迟抖动。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 检测 SMM</span>
</span></span><span class="line"><span class="cl">sudo hwlatdetector --threshold<span class="o">=</span><span class="m">50</span> --duration<span class="o">=</span><span class="m">60</span>
</span></span></code></pre></div><p>如果检测到大量超过阈值的延迟，且没有其他内核事件，很可能是 SMM 在作怪。这通常需要联系硬件厂商，或者更换硬件平台。</p>
<h3 id="62-优先级反转问题">6.2 优先级反转问题</h3>
<p>即使有 PREEMPT_RT 的优先级继承，优先级反转仍然可能发生：</p>
<pre tabindex="0"><code>高优先级任务 T1 等待锁 L
└─&gt; 持有锁 L 的低优先级任务 T2
    └─&gt; 被中等优先级任务 T3 抢占

结果：T1 等待 T3，优先级被反转！
</code></pre><p><strong>解决方案：</strong></p>
<ol>
<li><strong>减少锁的持有时间</strong>：这是最根本的解决方法</li>
<li><strong>使用优先级继承的锁</strong>：<code>pthread_mutexattr_setprotocol(&amp;attr, PTHREAD_PRIO_INHERIT)</code></li>
<li><strong>优先级天花板</strong>：预设锁的最高持有优先级</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">pthread_mutex_t</span> <span class="n">mutex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">pthread_mutexattr_t</span> <span class="n">attr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">pthread_mutexattr_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">attr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">pthread_mutexattr_setprotocol</span><span class="p">(</span><span class="o">&amp;</span><span class="n">attr</span><span class="p">,</span> <span class="n">PTHREAD_PRIO_INHERIT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">pthread_mutex_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attr</span><span class="p">);</span>
</span></span></code></pre></div><h3 id="63-网络延迟优化">6.3 网络延迟优化</h3>
<p>对于需要实时网络通信的应用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 设置网卡队列亲和性</span>
</span></span><span class="line"><span class="cl">sudo ethtool -X eth0 weight <span class="m">1</span> <span class="m">1</span> <span class="m">0</span> <span class="m">0</span>  <span class="c1"># 只使用前两个队列</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 禁用网卡自适应中断合并</span>
</span></span><span class="line"><span class="cl">sudo ethtool -C eth0 adaptive-rx off adaptive-tx off
</span></span><span class="line"><span class="cl">sudo ethtool -C eth0 rx-usecs <span class="m">1</span> tx-usecs <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用高性能网络调度</span>
</span></span><span class="line"><span class="cl">tc qdisc add dev eth0 root fq_codel
</span></span></code></pre></div><h2 id="七完整实时应用代码示例">七、完整实时应用代码示例</h2>
<p>以下是一个工业级实时控制循环的完整框架：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;signal.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;time.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;pthread.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/mman.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="cp">#define PERIOD_NS   1000000    </span><span class="c1">// 1ms 周期
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#define PRIORITY    80         </span><span class="c1">// 实时优先级
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="cp">#define CPU_AFFINITY 2         </span><span class="c1">// 绑定到 CPU 2
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">volatile</span> <span class="kt">int</span> <span class="n">running</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">sigint_handler</span><span class="p">(</span><span class="kt">int</span> <span class="n">sig</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">running</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">realtime_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">timespec</span> <span class="n">next_period</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 1. 设置 CPU 亲和性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">cpu_set_t</span> <span class="n">cpuset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_SET</span><span class="p">(</span><span class="n">CPU_AFFINITY</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">pthread_setaffinity_np</span><span class="p">(</span><span class="nf">pthread_self</span><span class="p">(),</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 2. 设置调度策略和优先级
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">struct</span> <span class="n">sched_param</span> <span class="n">param</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">sched_priority</span> <span class="o">=</span> <span class="n">PRIORITY</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="nf">pthread_setschedparam</span><span class="p">(</span><span class="nf">pthread_self</span><span class="p">(),</span> <span class="n">SCHED_FIFO</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">param</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 3. 预热 - 触发所有页面错误
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// （实际应用中应该在这里初始化所有资源）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    
</span></span><span class="line"><span class="cl">    <span class="c1">// 4. 获取初始时间
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nf">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">next_period</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;实时线程启动，周期: %ld ns</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">PERIOD_NS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 5. 主控制循环
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="n">running</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 等待下一个周期
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="nf">clock_nanosleep</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="n">TIMER_ABSTIME</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">next_period</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// ================= 控制逻辑开始 =================
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">        <span class="c1">// 读取传感器
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// 执行控制算法
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// 输出控制信号
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">        <span class="c1">// 性能统计（每隔 1 秒输出）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="k">if</span> <span class="p">(</span><span class="o">++</span><span class="n">count</span> <span class="o">%</span> <span class="mi">1000</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">struct</span> <span class="n">timespec</span> <span class="n">now</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">now</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="kt">long</span> <span class="kt">long</span> <span class="n">jitter</span> <span class="o">=</span> <span class="p">(</span><span class="n">now</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">-</span> <span class="n">next_period</span><span class="p">.</span><span class="n">tv_sec</span><span class="p">)</span> <span class="o">*</span> <span class="mi">1000000000LL</span> 
</span></span><span class="line"><span class="cl">                             <span class="o">+</span> <span class="p">(</span><span class="n">now</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">-</span> <span class="n">next_period</span><span class="p">.</span><span class="n">tv_nsec</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;周期 %llu，抖动: %lld ns</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">jitter</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// ================= 控制逻辑结束 =================
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">        <span class="c1">// 计算下一个唤醒时间
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="n">next_period</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">+=</span> <span class="n">PERIOD_NS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">next_period</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">&gt;=</span> <span class="mi">1000000000</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">next_period</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">-=</span> <span class="mi">1000000000</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">next_period</span><span class="p">.</span><span class="n">tv_sec</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;实时线程退出</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;=== PREEMPT_RT 实时应用框架 ===</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 1. 锁定所有内存
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="nf">mlockall</span><span class="p">(</span><span class="n">MCL_CURRENT</span> <span class="o">|</span> <span class="n">MCL_FUTURE</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;mlockall 失败&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 2. 注册信号处理
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nf">signal</span><span class="p">(</span><span class="n">SIGINT</span><span class="p">,</span> <span class="n">sigint_handler</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 3. 创建实时线程
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="kt">pthread_t</span> <span class="kr">thread</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">pthread_attr_t</span> <span class="n">attr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">pthread_attr_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">attr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">pthread_attr_setstacksize</span><span class="p">(</span><span class="o">&amp;</span><span class="n">attr</span><span class="p">,</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">);</span>  <span class="c1">// 1MB 栈
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="kr">thread</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">attr</span><span class="p">,</span> <span class="n">realtime_thread</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;创建线程失败&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// 4. 等待线程结束
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nf">pthread_join</span><span class="p">(</span><span class="kr">thread</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;程序正常退出</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>编译并运行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gcc -o realtime-app realtime-app.c -lpthread -lrt
</span></span><span class="line"><span class="cl">sudo chrt -f <span class="m">80</span> ./realtime-app
</span></span></code></pre></div><h2 id="八进阶方向与展望">八、进阶方向与展望</h2>
<h3 id="81-linux-66-主线实时支持">8.1 Linux 6.6+ 主线实时支持</h3>
<p>Linux 6.6 是一个里程碑版本，大量 PREEMPT_RT 核心代码终于合入了主线内核。现在只需在配置中启用 <code>CONFIG_PREEMPT_RT</code> 即可获得实时能力，不再需要外部补丁。</p>
<p>这标志着 PREEMPT_RT 已经从一个&quot;边缘&quot;项目变成了 Linux 内核的一等公民。</p>
<h3 id="82-与其他实时技术的结合">8.2 与其他实时技术的结合</h3>
<ul>
<li><strong>Xenomai</strong>：双内核架构，提供更硬的实时保证，但维护成本更高</li>
<li><strong>RTAI</strong>：另一个经典实时扩展，社区活跃度已不如从前</li>
<li>** Jailhouse **：Hypervisor 级别的隔离，适合需要最高安全等级的场景</li>
</ul>
<h3 id="83-未来发展趋势">8.3 未来发展趋势</h3>
<ol>
<li><strong>更多架构支持</strong>：RISC-V 的实时支持正在快速发展</li>
<li><strong>Ethernet TSN</strong>：时间敏感网络与实时操作系统的深度融合</li>
<li><strong>边缘计算</strong>：工业 4.0 对边缘节点的实时能力提出更高要求</li>
<li><strong>实时 AI</strong>：在实时约束下运行神经网络推理</li>
</ol>
<h2 id="总结">总结</h2>
<p>本文从实时系统的基本概念出发，深入解析了 PREEMPT_RT 的核心原理，提供了从内核编译、系统调优到性能测试的完整实战指南，并给出了工业级实时应用的代码框架。</p>
<p>PREEMPT_RT 最有价值的地方，不仅仅是它提供了微秒级的确定性，更在于它让我们可以在 Linux 这个成熟、丰富的生态系统中构建实时应用。你可以使用所有熟悉的工具、库和框架，同时获得硬实时的确定性保证。</p>
<p>但请记住：<strong>实时性是一个系统级的问题</strong>。内核只是其中一环，BIOS 配置、硬件选择、中断设计、驱动质量、应用架构——每一个环节都会影响最终的实时性能。要获得真正的确定性，需要从硬件到软件的全栈考量。</p>
<p>在工业 4.0 和智能机器人浪潮席卷而来的今天，实时 Linux 的重要性只会越来越凸显。PREEMPT_RT 的主线化标志着 Linux 作为工业级实时平台的真正成熟。希望本文能够帮助你在实时系统的道路上少走弯路，构建出真正可靠的实时应用。</p>
<p>（全文完，约 7200 字）</p>
]]></content:encoded></item></channel></rss>