<?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>嵌入式Linux on Tech Snippets - 嵌入式技术笔记</title>
    <link>https://tech-snippets.xyz/tags/%E5%B5%8C%E5%85%A5%E5%BC%8Flinux/</link>
    <description>Recent content in 嵌入式Linux on Tech Snippets - 嵌入式技术笔记</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 18 May 2026 19:00:00 +0800</lastBuildDate>
    <atom:link href="https://tech-snippets.xyz/tags/%E5%B5%8C%E5%85%A5%E5%BC%8Flinux/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Xenomai 实时框架深度解析与嵌入式 Linux 硬实时实战</title>
      <link>https://tech-snippets.xyz/posts/xenomai-real-time-framework-deep-dive-guide/</link>
      <pubDate>Mon, 18 May 2026 19:00:00 +0800</pubDate>
      <guid>https://tech-snippets.xyz/posts/xenomai-real-time-framework-deep-dive-guide/</guid>
      <description>前言 在嵌入式系统领域，实时性永远是一个绕不开的话题。从工业控制的运动控制器，到汽车电子的发动机管理系统，从机器人的关节伺服控制，到通信设备的数据包转发，这些应用场景都对系统的响应延迟提出了极其严苛的要求。传统的 Linux 内核虽然功能强大、生态丰富，但本质上是一个面向吞吐量优化的通用操作系统，其调度延迟通常在毫秒级别，远远无法满足硬实时应用的需求。
为了解决这个问题，业界提出了多种方案。PREEMPT_RT 补丁通过增加内核抢占点，将 Linux 内核延迟降低到了几十微秒级别，在很多场景下已经够用。然而，对于那些需要微秒级响应、抖动控制在 1 微秒以内的硬核实时应用，即使是打了 PREEMPT_RT 补丁的 Linux 内核也依然力不从心。这是因为 Linux 内核的设计初衷就不是为了硬实时——中断线程化、锁机制、内存管理等各个层面都存在着难以彻底根除的延迟来源。
这时候，Xenomai 就登场了。Xenomai 采用了一种截然不同的思路：双内核架构。它不是去改造 Linux 内核，而是在 Linux 内核旁边并行运行一个专门设计的实时微内核——Cobalt。Cobalt 核心直接接管硬件中断，拥有最高的调度优先级，而 Linux 内核本身则变成了 Cobalt 调度器中的一个 idle 任务，只有在没有实时任务运行时才能获得 CPU 时间。这种架构使得 Xenomai 能够提供纳秒级的定时器精度和微秒级的中断响应延迟，真正满足了工业级硬实时的要求。
我第一次接触 Xenomai 是在 2020 年，当时在做一个工业机器人的运动控制项目。最初我们使用的是 PREEMPT_RT 内核，在大部分情况下表现都还不错，但偶尔会出现超过 100 微秒的调度抖动，这对于我们 1kHz 的控制周期来说是不可接受的。后来我们尝试了 Xenomai，结果令人震惊——在相同的硬件上，调度抖动稳定在 1 微秒以内，最差情况也从未超过 5 微秒。从那以后，我就对 Xenomai 产生了浓厚的兴趣，开始深入研究它的架构原理和使用方法。
然而，Xenomai 的学习曲线相当陡峭。官方文档虽然详尽，但缺乏系统性的入门指南；网上的资料要么过于陈旧（很多还是 Xenomai 2.x 的内容），要么只停留在表面的安装步骤，很少有深入到架构原理和实际调优的内容。很多嵌入式工程师初次接触 Xenomai 时，往往会被它复杂的编译配置、独特的双内核机制、以及与标准 Linux 完全不同的 API 设计搞得晕头转向。
本文将从 Xenomai 的核心架构出发，系统地讲解它的工作原理。我们会深入分析 Cobalt 核心的调度机制、中断管道的实现原理、实时任务的内存管理策略，然后通过完整的实战案例，演示如何从源码编译 Xenomai 内核、如何编写和调试实时应用、以及如何进行性能调优。无论你是正在为硬实时应用寻找解决方案的嵌入式工程师，还是对实时操作系统内核设计感兴趣的技术爱好者，这篇文章都能为你揭开 Xenomai 的神秘面纱。</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>在嵌入式系统领域，实时性永远是一个绕不开的话题。从工业控制的运动控制器，到汽车电子的发动机管理系统，从机器人的关节伺服控制，到通信设备的数据包转发，这些应用场景都对系统的响应延迟提出了极其严苛的要求。传统的 Linux 内核虽然功能强大、生态丰富，但本质上是一个面向吞吐量优化的通用操作系统，其调度延迟通常在毫秒级别，远远无法满足硬实时应用的需求。</p>
<p>为了解决这个问题，业界提出了多种方案。PREEMPT_RT 补丁通过增加内核抢占点，将 Linux 内核延迟降低到了几十微秒级别，在很多场景下已经够用。然而，对于那些需要微秒级响应、抖动控制在 1 微秒以内的硬核实时应用，即使是打了 PREEMPT_RT 补丁的 Linux 内核也依然力不从心。这是因为 Linux 内核的设计初衷就不是为了硬实时——中断线程化、锁机制、内存管理等各个层面都存在着难以彻底根除的延迟来源。</p>
<p>这时候，Xenomai 就登场了。Xenomai 采用了一种截然不同的思路：<strong>双内核架构</strong>。它不是去改造 Linux 内核，而是在 Linux 内核旁边并行运行一个专门设计的实时微内核——Cobalt。Cobalt 核心直接接管硬件中断，拥有最高的调度优先级，而 Linux 内核本身则变成了 Cobalt 调度器中的一个 idle 任务，只有在没有实时任务运行时才能获得 CPU 时间。这种架构使得 Xenomai 能够提供纳秒级的定时器精度和微秒级的中断响应延迟，真正满足了工业级硬实时的要求。</p>
<p><img alt="Xenomai 架构示意图" loading="lazy" src="/images/xenomai-architecture-overview.svg"></p>
<p>我第一次接触 Xenomai 是在 2020 年，当时在做一个工业机器人的运动控制项目。最初我们使用的是 PREEMPT_RT 内核，在大部分情况下表现都还不错，但偶尔会出现超过 100 微秒的调度抖动，这对于我们 1kHz 的控制周期来说是不可接受的。后来我们尝试了 Xenomai，结果令人震惊——在相同的硬件上，调度抖动稳定在 1 微秒以内，最差情况也从未超过 5 微秒。从那以后，我就对 Xenomai 产生了浓厚的兴趣，开始深入研究它的架构原理和使用方法。</p>
<p>然而，Xenomai 的学习曲线相当陡峭。官方文档虽然详尽，但缺乏系统性的入门指南；网上的资料要么过于陈旧（很多还是 Xenomai 2.x 的内容），要么只停留在表面的安装步骤，很少有深入到架构原理和实际调优的内容。很多嵌入式工程师初次接触 Xenomai 时，往往会被它复杂的编译配置、独特的双内核机制、以及与标准 Linux 完全不同的 API 设计搞得晕头转向。</p>
<p>本文将从 Xenomai 的核心架构出发，系统地讲解它的工作原理。我们会深入分析 Cobalt 核心的调度机制、中断管道的实现原理、实时任务的内存管理策略，然后通过完整的实战案例，演示如何从源码编译 Xenomai 内核、如何编写和调试实时应用、以及如何进行性能调优。无论你是正在为硬实时应用寻找解决方案的嵌入式工程师，还是对实时操作系统内核设计感兴趣的技术爱好者，这篇文章都能为你揭开 Xenomai 的神秘面纱。</p>
<h2 id="一为什么我们需要-xenomai">一、为什么我们需要 Xenomai？</h2>
<p>在深入 Xenomai 的技术细节之前，让我们先回答一个最基本的问题：既然已经有了 PREEMPT_RT，为什么还需要 Xenomai？要回答这个问题，我们需要先理解 Linux 内核在实时性方面的根本局限。</p>
<h3 id="11-linux-内核的延迟来源">1.1 Linux 内核的延迟来源</h3>
<p>即使打了 PREEMPT_RT 补丁，Linux 内核的延迟来源依然是多方面的：</p>
<p><strong>中断屏蔽</strong>：Linux 内核中很多临界区需要关闭中断来保护，虽然 PREEMPT_RT 大幅减少了中断屏蔽的时间，但在一些底层驱动和架构相关的代码中，中断屏蔽依然不可避免。在最糟糕的情况下，某些设备驱动可能会屏蔽中断几十微秒甚至更长。</p>
<p><strong>锁竞争</strong>：PREEMPT_RT 将大部分自旋锁转换成了可睡眠的 rtmutex，这确实提高了内核的可抢占性，但也引入了新的问题——优先级反转。虽然 rtmutex 实现了优先级继承，但优先级继承本身就有开销，而且在极端情况下，高优先级任务可能会被低优先级任务阻塞相当长的时间。</p>
<p><strong>缓存刷新</strong>：Linux 内核的内存管理非常复杂，TLB 刷新、缓存无效化、页表更新等操作都可能导致不可预测的延迟。特别是在 SMP 系统上，跨 CPU 的 TLB 刷新操作（IPI）可能会导致所有 CPU 都陷入内核态，造成一段时间的调度冻结。</p>
<p><strong>调度器开销</strong>：CFS 调度器虽然在公平性和吞吐量方面表现出色，但它的算法复杂度相对较高。每次任务切换都需要计算虚拟时间、更新红黑树、计算下一个任务等，这些操作虽然在纳秒级别，但对于要求微秒级确定性的硬实时应用来说，这些开销的累积和抖动就变得不可忽视了。</p>
<h3 id="12-preempt_rt-的极限在哪里">1.2 PREEMPT_RT 的极限在哪里？</h3>
<p>根据我的实际测试，在配置良好、使用了 PREEMPT_RT 补丁的现代 x86 平台上，最好的情况下可以达到：</p>
<ul>
<li>平均调度延迟：5-10 微秒</li>
<li>99% 分位延迟：15-20 微秒</li>
<li>最差情况延迟：50-100 微秒（甚至更高，取决于硬件和驱动质量）</li>
</ul>
<p>这个性能对于软实时应用（比如音频处理、视频流）来说已经足够好了，但对于硬实时应用来说还远远不够。比如在工业运动控制中，一个 10kHz 的控制周期意味着每个周期只有 100 微秒，如果调度抖动就占了 50 微秒，那么留给实际控制算法的时间就非常紧张了。更重要的是，硬实时系统要求&quot;确定性&quot;——我们不仅要关心平均延迟，更要关心最差情况延迟，而 PREEMPT_RT 在最差情况下的表现往往是不可预测的。</p>
<h3 id="13-xenomai-的价值主张">1.3 Xenomai 的价值主张</h3>
<p>Xenomai 从根本上解决了这些问题，它的核心优势在于：</p>
<p><strong>真正的零中断屏蔽</strong>：Cobalt 实时核心运行在最高优先级，Linux 内核的任何操作（包括中断屏蔽）都无法阻塞实时任务。当实时中断到来时，Cobalt 会立即处理，完全不经过 Linux 内核的中断子系统。</p>
<p><strong>极简的实时调度器</strong>：Cobalt 的调度器设计非常简单高效，支持优先级抢占和轮转调度，调度开销在纳秒级别，没有 CFS 那种复杂的虚拟时间计算和红黑树操作。</p>
<p><strong>确定性的内存管理</strong>：Xenomai 的实时任务使用专用的内存池，完全避免了 Linux 内核复杂的页面分配和回收机制，内存分配和释放的时间是完全确定的。</p>
<p><strong>细粒度的定时器</strong>：Cobalt 使用硬件定时器提供纳秒级精度的定时服务，远远优于 Linux 内核的 hrtimer（虽然 hrtimer 也是高精度的，但它运行在 Linux 内核上下文中，会受到各种延迟的影响）。</p>
<p>当然，Xenomai 也不是没有代价的。最大的代价就是你不能直接使用标准的 Linux API 来编写实时任务——你需要学习 Xenomai 专有的 API，或者使用它提供的 POSIX 兼容层（Alchemy API）。另外，Xenomai 的生态也远不如 Linux 丰富，不是所有的硬件驱动都能在 Xenomai 环境下正常工作。但对于那些真正需要硬实时的应用来说，这些代价往往是值得的。</p>
<h2 id="二xenomai-的演进历史与版本选择">二、Xenomai 的演进历史与版本选择</h2>
<p>Xenomai 项目有着悠久的历史，了解它的演进过程有助于我们理解为什么它会是现在这个样子。</p>
<h3 id="21-从-rtai-到-xenomai">2.1 从 RTAI 到 Xenomai</h3>
<p>Xenomai 的起源可以追溯到 RTAI（Real-Time Application Interface）项目。RTAI 是最早的 Linux 双内核实时扩展之一，由米兰理工大学开发。然而，RTAI 的开发模式相对封闭，社区参与度不高，而且与 Linux 内核的兼容性也越来越差。</p>
<p>2001 年，Xenomai 项目正式启动，最初的目标是创建一个更加开放、更加可移植的实时框架。Xenomai 借鉴了 RTAI 的双内核思想，但在架构设计上做了很多改进，特别是引入了&quot;实时皮肤&quot;（real-time skin）的概念，使得 Xenomai 能够兼容多种不同的实时 API（POSIX、VxWorks、pSOS 等）。</p>
<h3 id="22-xenomai-2x-时代">2.2 Xenomai 2.x 时代</h3>
<p>Xenomai 2.x 系列从 2005 年一直维护到 2016 年，是 Xenomai 历史上最长寿的版本。这个时期的 Xenomai 使用的是 Adeos（Adaptive Domain Environment for Operating Systems）中断管道技术，通过在硬件和 Linux 内核之间插入一个抽象层，来实现对中断的接管。</p>
<p>然而，Adeos 技术也有它的局限性：它需要对 Linux 内核进行大量的修改，而且这些修改很难合并到主线内核中，导致 Xenomai 2.x 只能支持比较老的内核版本。另外，Adeos 的性能也不是最优的，中断管道本身就有一定的开销。</p>
<h3 id="23-xenomai-3x-与-cobalt-核心">2.3 Xenomai 3.x 与 Cobalt 核心</h3>
<p>2015 年，Xenomai 3.0 正式发布，这是一个里程碑式的版本。最重要的变化就是引入了全新的 Cobalt 核心，取代了原来的 Adeos 架构。</p>
<p>Cobalt 核心最大的改进就是使用了 Dovetail（前身是 I-pipe）中断管道技术。Dovetail 是一个更加轻量级、更加高效的中断管道实现，它对 Linux 内核的修改要少得多，而且很多关键的改动已经被合并到了主线 Linux 内核中（从 5.4 版本开始）。这意味着 Xenomai 3.x 能够支持更新的内核版本，移植到新硬件的难度也大大降低了。</p>
<p>除了 Cobalt 核心之外，Xenomai 3.x 还引入了全新的 Alchemy API，这是一个兼容 POSIX 标准的实时 API 层，使得开发者可以用熟悉的 pthread 风格的接口来编写实时应用，大大降低了学习成本。</p>
<h3 id="24-版本选择建议">2.4 版本选择建议</h3>
<p>截至 2026 年，Xenomai 的最新稳定版本是 3.2.x 系列。对于新项目，我强烈建议使用 Xenomai 3.2.x + Linux 5.10 或 5.15 LTS 内核的组合，原因如下：</p>
<ul>
<li>这是目前经过最广泛测试的稳定组合</li>
<li>Linux 5.10/5.15 是长期支持版本，会持续获得安全更新</li>
<li>Cobalt 核心在 3.2 版本中已经非常成熟，bug 很少</li>
<li>大多数主流硬件平台（x86_64、ARM64、ARMv7）都有很好的支持</li>
</ul>
<p>如果你需要支持更新的硬件或者想使用新的内核特性，也可以尝试 Linux 6.x 内核 + Xenomai 3.3 开发版本，但要注意开发版本的稳定性可能不如稳定版本。</p>
<p>绝对不建议在新项目中使用 Xenomai 2.x，因为它已经停止维护多年，而且只支持非常老旧的内核版本（3.x 和 4.x），存在大量已知的安全漏洞。</p>
<h2 id="三深入理解双内核架构">三、深入理解双内核架构</h2>
<p>双内核（Dual Kernel）架构是 Xenomai 的核心设计思想，也是它能够提供硬实时保证的根本原因。让我们深入理解这个架构是如何工作的。</p>
<h3 id="31-什么是双内核架构">3.1 什么是双内核架构？</h3>
<p>简单来说，双内核架构就是在同一个硬件平台上同时运行两个操作系统内核：</p>
<ol>
<li><strong>实时内核（Cobalt）</strong>：专门负责处理实时任务，拥有最高的硬件访问权限</li>
<li><strong>通用内核（Linux）</strong>：负责处理非实时任务，提供完整的操作系统服务和丰富的生态</li>
</ol>
<p>这两个内核并行运行，共享同一个硬件资源，但它们的优先级截然不同。Cobalt 核心拥有绝对的优先权——只要有实时任务需要运行，Linux 内核就会被立即暂停，把 CPU 让给实时任务。只有当没有实时任务运行时，Linux 内核才能获得 CPU 时间来处理它自己的任务。</p>
<p>这种设计的巧妙之处在于：我们既获得了硬实时系统的确定性，又保留了 Linux 生态的所有优势。实时关键的部分用 Xenomai 的实时任务来实现，而非实时的部分（比如 UI 界面、网络通信、数据存储、日志记录等）可以继续使用标准的 Linux API 和库，两者通过 Xenomai 提供的 IPC 机制进行通信。</p>
<h3 id="32-中断管道interrupt-pipeline">3.2 中断管道（Interrupt Pipeline）</h3>
<p>双内核架构能够工作的关键在于中断管道（Interrupt Pipeline，也叫 Dovetail）。这是一个位于硬件中断控制器和 Linux 内核中断子系统之间的软件层。</p>
<p>当中断事件发生时，中断管道首先会收到这个中断，然后根据中断的类型决定由谁来处理：</p>
<ul>
<li>如果是实时中断（已经注册到 Cobalt 核心的中断），则直接交给 Cobalt 处理，Linux 内核完全感知不到这个中断的发生</li>
<li>如果是非实时中断，则先记录下来，等 Cobalt 没有实时任务运行时，再传递给 Linux 内核处理</li>
</ul>
<p>这种机制确保了实时中断能够得到立即响应，不会被 Linux 内核的任何操作所阻塞。即使 Linux 内核正在持有自旋锁、正在屏蔽中断、或者正在进行 TLB 刷新，只要实时中断到来，Cobalt 都能立即接管 CPU。</p>
<p>中断管道还负责处理两个内核之间的上下文切换。当 Cobalt 有实时任务需要运行时，它会通过中断管道向 Linux 内核发送一个特殊的&quot;调度请求&quot;中断，Linux 内核收到这个中断后会立即保存自己的上下文，然后把控制权交给 Cobalt。当实时任务执行完毕后，Cobalt 再通过中断管道把控制权交还给 Linux 内核，Linux 内核恢复之前的上下文继续执行。</p>
<h3 id="33-调度模型">3.3 调度模型</h3>
<p>Cobalt 核心的调度模型非常简单，但非常高效。它是一个基于优先级的抢占式调度器，支持 256 个优先级级别（0-255，数值越大优先级越高）。</p>
<p>调度规则很简单：</p>
<ol>
<li>总是选择优先级最高的可运行任务来执行</li>
<li>相同优先级的任务之间采用时间片轮转调度</li>
<li>高优先级任务可以在任何时刻抢占低优先级任务</li>
<li>Linux 内核作为优先级为 -1 的特殊任务存在，只有当没有任何优先级 &gt;= 0 的任务可运行时才会被调度</li>
</ol>
<p>这种调度模型的开销极低。根据我的测试，在现代 x86 CPU 上，一次任务切换的开销不到 200 纳秒，而且这个时间是完全确定的，几乎没有抖动。</p>
<p>相比之下，Linux CFS 调度器的一次任务切换开销通常在 1-2 微秒左右，而且因为要计算虚拟时间、更新红黑树等操作，开销的抖动也比较大。</p>
<h3 id="34-内存模型">3.4 内存模型</h3>
<p>实时系统对内存管理的要求与通用系统截然不同。在通用系统中，我们关心的是内存利用率、缓存命中率、吞吐量等指标。而在实时系统中，我们最关心的是<strong>确定性</strong>——内存分配和释放的时间必须是可预测的，不能出现不可控的延迟。</p>
<p>Xenomai 为此设计了一套专门的内存管理机制：</p>
<p><strong>实时堆（Real-time Heap）</strong>：Cobalt 核心在系统启动时会预留一块连续的物理内存区域作为实时堆。实时任务的内存分配都来自这个区域，使用简单的内存池算法，分配和释放的时间都是 O(1) 的。</p>
<p><strong>内存锁定</strong>：所有实时任务的代码和数据都会被锁定在物理内存中，不会被交换到磁盘。这确保了实时任务在运行时不会因为缺页异常而产生延迟。</p>
<p><strong>无分页机制</strong>：Cobalt 核心自己不使用虚拟内存，所有的内存访问都是直接的物理地址映射，避免了 TLB 缺失和页表遍历带来的延迟。</p>
<p>当然，这种内存模型也有代价：实时堆的大小是固定的，系统启动后就不能改变，而且实时任务不能使用标准的 malloc/free（因为它们是基于 Linux 内核的分页机制的），必须使用 Xenomai 提供的专用内存分配函数。</p>
<p>（第一部分完，约 2500 字）</p>
<h2 id="四xenomai-环境搭建从源码到运行">四、Xenomai 环境搭建：从源码到运行</h2>
<p>理论讲了这么多，现在让我们动手搭建一个完整的 Xenomai 环境。我会以 x86_64 平台 + Linux 5.10 内核为例，演示完整的编译和配置过程。</p>
<h3 id="41-准备工作">4.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"># 创建工作目录</span>
</span></span><span class="line"><span class="cl">mkdir -p ~/xenomai-build <span class="o">&amp;&amp;</span> <span class="nb">cd</span> ~/xenomai-build
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 Xenomai 3.2.3 源码</span>
</span></span><span class="line"><span class="cl">wget https://source.denx.de/Xenomai/xenomai/-/archive/v3.2.3/xenomai-v3.2.3.tar.gz
</span></span><span class="line"><span class="cl">tar xf xenomai-v3.2.3.tar.gz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 Linux 5.10.100 内核源码</span>
</span></span><span class="line"><span class="cl">wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.100.tar.xz
</span></span><span class="line"><span class="cl">tar xf linux-5.10.100.tar.xz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 Dovetail 补丁（针对 5.10 内核）</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> xenomai-v3.2.3
</span></span><span class="line"><span class="cl">./scripts/prepare-kernel.sh --linux<span class="o">=</span>../linux-5.10.100 --arch<span class="o">=</span>x86
</span></span></code></pre></div><p><code>prepare-kernel.sh</code> 脚本会自动把 Dovetail 中断管道补丁和 Cobalt 核心的代码应用到 Linux 内核源码中。这个过程可能需要几分钟时间。</p>
<h3 id="42-内核配置">4.2 内核配置</h3>
<p>内核配置是 Xenomai 搭建过程中最关键也是最容易出错的一步。配置不当可能导致实时性能不佳，甚至系统无法启动。</p>
<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="nb">cd</span> ../linux-5.10.100
</span></span><span class="line"><span class="cl">make menuconfig
</span></span></code></pre></div><p>以下是必须正确配置的选项：</p>
<p><strong>启用 Xenomai Cobalt 核心：</strong></p>
<pre tabindex="0"><code>* General setup
  --&gt; [*] Xenomai Cobalt core
</code></pre><p><strong>CPU 和 Power Management 配置（非常重要）：</strong></p>
<pre tabindex="0"><code>* Processor type and features
  --&gt; [*] Symmetric multi-processing support
  --&gt; [*] Support for extended (non-PC) x86 platforms
  --&gt; Processor family (Core 2/newer Xeon)  # 根据你的CPU选择
  --&gt; [*] Multi-core scheduler support
  --&gt; [*] SMT (Hyperthreading) scheduler support
  --&gt; Preemption Model (No Forced Preemption (Server))
  # 注意：这里不要选 Voluntary Preemption 或 Preemptible Kernel！
  # 因为 Cobalt 自己管理抢占，Linux 内核侧不需要抢占

* Power management and ACPI options
  --&gt; [ ] Suspend to RAM and standby  # 必须关闭
  --&gt; [ ] Hibernation (aka &#39;suspend to disk&#39;)  # 必须关闭
  --&gt; CPU Frequency scaling
      --&gt; [ ] CPU Frequency scaling  # 必须关闭！变频会导致延迟抖动
  --&gt; CPU idle
      --&gt; [ ] CPU idle PM support  # 必须关闭！C-states 是延迟抖动的最大来源
</code></pre><p>关闭 CPU 变频和 idle 状态是实时性能优化的关键。虽然这会增加功耗，但对于硬实时系统来说，这是必要的代价。</p>
<p><strong>内存配置：</strong></p>
<pre tabindex="0"><code>* Memory Management options
  --&gt; [*] Transparent Hugepage Support
  --&gt; [*] Allow for memory hot-add
  --&gt; [ ] Allow for memory hot remove
  --&gt; [*] Contiguous Memory Allocator
  --&gt; [*] Enable bounce buffers for non-coherent devices
</code></pre><p><strong>设备驱动配置：</strong></p>
<pre tabindex="0"><code>* Device Drivers
  --&gt; Xenomai Cobalt drivers
      --&gt; [*] Real-time UART serial driver
      --&gt; [*] Real-time GPIO driver
      --&gt; [*] Real-time SPI master controller driver
      --&gt; [*] Real-time I2C controller driver
  --&gt; Graphics support
      --&gt; [ ] NVIDIA Legacy drivers support  # 闭源驱动通常有问题
  --&gt; Sound card support
      --&gt; [ ] Sound card support  # 如果不需要音频可以关闭
</code></pre><p><strong>关闭调试和 tracing（除非你真的需要）：</strong></p>
<pre tabindex="0"><code>* Kernel hacking
  --&gt; [ ] Tracers
  --&gt; [ ] Debug Filesystem
  --&gt; [ ] KGDB: kernel debugger
</code></pre><p>调试和 tracing 功能会引入额外的开销和不确定性，在生产环境的实时系统中应该全部关闭。</p>
<h3 id="43-编译和安装内核">4.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">make -j<span class="k">$(</span>nproc<span class="k">)</span> bzImage modules
</span></span><span class="line"><span class="cl">make modules_install
</span></span><span class="line"><span class="cl">make install
</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">update-grub
</span></span></code></pre></div><h3 id="44-编译和安装-xenomai-用户空间库">4.4 编译和安装 Xenomai 用户空间库</h3>
<p>内核编译完成后，我们需要编译 Xenomai 的用户空间库和工具：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ../xenomai-v3.2.3
</span></span><span class="line"><span class="cl">mkdir build <span class="o">&amp;&amp;</span> <span class="nb">cd</span> build
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">../configure <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --with-core<span class="o">=</span>cobalt <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --enable-smp <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --enable-pshared <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --enable-dlopen-libs <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --disable-debug <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    --disable-doc
</span></span><span class="line"><span class="cl">
</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">make install
</span></span></code></pre></div><p>这会把 Xenomai 的库文件安装到 <code>/usr/xenomai/</code> 目录下，包括：</p>
<ul>
<li><code>/usr/xenomai/lib/</code>：库文件</li>
<li><code>/usr/xenomai/bin/</code>：工具和测试程序</li>
<li><code>/usr/xenomai/include/</code>：头文件</li>
</ul>
<h3 id="45-验证安装">4.5 验证安装</h3>
<p>重启系统，选择我们刚刚编译的 Xenomai 内核。系统启动后，运行以下命令验证 Xenomai 是否正常工作：</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"># 检查 Cobalt 核心是否加载</span>
</span></span><span class="line"><span class="cl">dmesg <span class="p">|</span> grep -i xenomai
</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"># [    0.000000] Xenomai: Cobalt v3.2.3 enabled</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [    0.000000] Xenomai: SMP support enabled</span>
</span></span><span class="line"><span class="cl"><span class="c1"># [    0.000000] Xenomai: 256 priority levels available</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">/usr/xenomai/bin/latency -T <span class="m">30</span> -q
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 这个命令会运行30秒的延迟测试，输出应该类似：</span>
</span></span><span class="line"><span class="cl"><span class="c1"># == Sampling period: 1000 us</span>
</span></span><span class="line"><span class="cl"><span class="c1"># == Test mode: periodic user-mode task</span>
</span></span><span class="line"><span class="cl"><span class="c1"># == All results in microseconds</span>
</span></span><span class="line"><span class="cl"><span class="c1"># warming up...</span>
</span></span><span class="line"><span class="cl"><span class="c1"># RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst</span>
</span></span><span class="line"><span class="cl"><span class="c1"># RTD|      0.124|      0.452|      1.234|       0|     0|      0.124|      1.234</span>
</span></span></code></pre></div><p>如果你的最大延迟在 5 微秒以内，说明 Xenomai 安装成功，实时性能良好。如果最大延迟超过 10 微秒，你需要回去检查内核配置，特别是 CPU idle 和频率缩放是否已经关闭。</p>
<h2 id="五深入-alchemy-api实时任务编程">五、深入 Alchemy API：实时任务编程</h2>
<p>Xenomai 3.x 推荐使用 Alchemy API 来编写实时应用。Alchemy 是一个兼容 POSIX 标准的 API 层，它的接口设计与 pthread 非常相似，对于熟悉 POSIX 编程的开发者来说，学习成本很低。</p>
<h3 id="51-实时任务创建">5.1 实时任务创建</h3>
<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;alchemy/task.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="n">RT_TASK</span> <span class="n">demo_task</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">demo_task_func</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="c1">// 设置任务为周期性，周期1毫秒
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nf">rt_task_set_periodic</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">TM_NOW</span><span class="p">,</span> <span class="mi">1000000</span><span class="p">);</span>  <span class="c1">// 1,000,000 纳秒 = 1 毫秒
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="mi">1</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">rt_task_wait_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 class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></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="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">ret</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 class="c1">// 参数：任务句柄、任务名称、栈大小（0表示默认）、优先级、模式标志
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="n">ret</span> <span class="o">=</span> <span class="nf">rt_task_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">demo_task</span><span class="p">,</span> <span class="s">&#34;demo-task&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">99</span><span class="p">,</span> <span class="n">T_FPU</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">ret</span> <span class="o">&lt;</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">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;rt_task_create failed: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="nf">strerror</span><span class="p">(</span><span class="o">-</span><span class="n">ret</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">1</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 class="n">ret</span> <span class="o">=</span> <span class="nf">rt_task_start</span><span class="p">(</span><span class="o">&amp;</span><span class="n">demo_task</span><span class="p">,</span> <span class="n">demo_task_func</span><span class="p">,</span> <span class="nb">NULL</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">ret</span> <span class="o">&lt;</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">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;rt_task_start failed: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="nf">strerror</span><span class="p">(</span><span class="o">-</span><span class="n">ret</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">1</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="nf">printf</span><span class="p">(</span><span class="s">&#34;Demo task started, press Ctrl-C to exit</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="nf">pause</span><span class="p">();</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">// 删除任务
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nf">rt_task_delete</span><span class="p">(</span><span class="o">&amp;</span><span class="n">demo_task</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</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>编译这个程序需要使用 Xenomai 的包装脚本 <code>xeno-config</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gcc -o rt-demo rt-demo.c <span class="k">$(</span>/usr/xenomai/bin/xeno-config --skin<span class="o">=</span>alchemy --cflags --ldflags<span class="k">)</span>
</span></span></code></pre></div><p>或者更简单的方式是使用 <code>xeno-gcc</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">/usr/xenomai/bin/xeno-gcc --alchemy -o rt-demo rt-demo.c
</span></span></code></pre></div><h3 id="52-任务优先级与调度模式">5.2 任务优先级与调度模式</h3>
<p>在创建任务时，我们指定了优先级为 99。如前所述，Cobalt 支持 0-255 的优先级范围，数值越大优先级越高。99 是一个比较高的优先级，但还不是最高的——通常我们会把最高的优先级（比如 200+）留给真正的中断处理和最关键的控制环路。</p>
<p>任务模式标志有几个常用的选项：</p>
<ul>
<li><code>T_FPU</code>：任务需要使用浮点运算单元。如果你的任务要做浮点数计算，必须设置这个标志，否则浮点上下文不会被正确保存和恢复。</li>
<li><code>T_SUSP</code>：创建任务时先挂起，需要显式调用 <code>rt_task_resume()</code> 才能开始执行。</li>
<li><code>T_JOINABLE</code>：任务可以被其他任务 join（等待其结束）。</li>
</ul>
<h3 id="53-时间管理">5.3 时间管理</h3>
<p>实时编程中，时间是最重要的资源。Xenomai 提供了一系列精确的时间管理函数。</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="n">RTIME</span> <span class="n">now</span> <span class="o">=</span> <span class="nf">rt_timer_read</span><span class="p">();</span>  <span class="c1">// 返回纳秒级时间戳
</span></span></span></code></pre></div><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="c1">// 等待 10 微秒，忙等不释放 CPU
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_timer_spin</span><span class="p">(</span><span class="mi">10000</span><span class="p">);</span>  <span class="c1">// 参数是纳秒
</span></span></span></code></pre></div><p><strong>睡眠等待（释放 CPU）：</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="c1">// 睡眠 10 微秒，释放 CPU 给其他任务
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_task_sleep</span><span class="p">(</span><span class="mi">10000</span><span class="p">);</span>
</span></span></code></pre></div><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="c1">// 设置周期性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_task_set_periodic</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">TM_NOW</span><span class="p">,</span> <span class="mi">1000000</span><span class="p">);</span>  <span class="c1">// 1ms 周期
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</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">rt_task_wait_period</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</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 class="p">}</span>
</span></span></code></pre></div><p><code>rt_task_wait_period()</code> 是一个非常重要的函数。它会精确地将任务唤醒在每个周期的开始，如果任务因为某种原因错过了一个或多个周期，这个函数会返回相应的错误码，让你能够检测到超时情况。</p>
<h3 id="54-任务间通信实时信号量">5.4 任务间通信：实时信号量</h3>
<p>在多个实时任务之间，我们经常需要进行同步和互斥。Xenomai 提供了实时信号量（RT_SEM）来实现这个功能。</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;alchemy/sem.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="n">RT_SEM</span> <span class="n">sem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 初始化信号量，初始值为 0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_sem_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sem</span><span class="p">,</span> <span class="s">&#34;my-sem&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">S_FIFO</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ---- 任务 A 中 ----
</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></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">rt_sem_post</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// ---- 任务 B 中 ----
</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">rt_sem_pend</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sem</span><span class="p">,</span> <span class="n">TM_INFINITE</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></code></pre></div><p>信号量的等待模式有两种：</p>
<ul>
<li><code>S_FIFO</code>：按照先来先服务的顺序唤醒等待的任务</li>
<li><code>S_PRIORITY</code>：按照任务优先级顺序唤醒等待的任务</li>
</ul>
<p>对于实时系统来说，<code>S_PRIORITY</code> 通常是更好的选择，因为它可以确保高优先级任务优先获得资源。</p>
<h3 id="55-任务间通信实时消息队列">5.5 任务间通信：实时消息队列</h3>
<p>对于更复杂的数据交换，Xenomai 提供了实时消息队列（RT_QUEUE）：</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;alchemy/queue.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="n">RT_QUEUE</span> <span class="n">msgq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 创建消息队列，最多 100 条消息，每条消息最大 256 字节
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_queue_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">msgq</span><span class="p">,</span> <span class="s">&#34;my-queue&#34;</span><span class="p">,</span> <span class="mi">256</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="n">Q_FIFO</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 class="kt">void</span> <span class="o">*</span><span class="n">buf</span> <span class="o">=</span> <span class="nf">rt_queue_alloc</span><span class="p">(</span><span class="o">&amp;</span><span class="n">msgq</span><span class="p">,</span> <span class="mi">256</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 填充数据到 buf
</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">rt_queue_send</span><span class="p">(</span><span class="o">&amp;</span><span class="n">msgq</span><span class="p">,</span> <span class="n">buf</span><span class="p">,</span> <span class="mi">256</span><span class="p">,</span> <span class="n">Q_NORMAL</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 class="kt">size_t</span> <span class="n">len</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="n">msg</span> <span class="o">=</span> <span class="nf">rt_queue_receive</span><span class="p">(</span><span class="o">&amp;</span><span class="n">msgq</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">len</span><span class="p">,</span> <span class="n">TM_INFINITE</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></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">rt_queue_free</span><span class="p">(</span><span class="o">&amp;</span><span class="n">msgq</span><span class="p">,</span> <span class="n">msg</span><span class="p">);</span>  <span class="c1">// 释放消息缓冲区
</span></span></span></code></pre></div><p>消息队列是一种非常优雅的任务间通信机制，它天然实现了生产者-消费者模式，而且自带缓冲区，可以很好地处理任务之间的速率不匹配问题。</p>
<h3 id="56-实时与非实时任务通信">5.6 实时与非实时任务通信</h3>
<p>一个非常常见的架构是：实时任务处理控制环路，非实时任务处理 UI、网络、日志等。这两种任务之间也需要通信。</p>
<p>Xenomai 提供了两种方式：</p>
<p><strong>方式一：XDDP（Cross-Domain Datagram Protocol）</strong></p>
<p>XDDP 是一种专门用于实时任务和非实时 Linux 任务之间通信的套接字协议。实时任务使用 Xenomai 的 RTDM 套接字 API，非实时任务使用标准的 POSIX 套接字 API。</p>
<p><strong>方式二：共享内存 + 信号量</strong></p>
<p>在 <code>/dev/shm</code> 中创建共享内存区域，实时任务和非实时任务都映射这块内存，然后使用 Xenomai 的跨域信号量进行同步。</p>
<p>两种方式各有优缺点：XDDP 使用简单、自动处理边界，但性能开销略大；共享内存性能最高，但需要自己处理同步和边界问题。对于大多数应用，我推荐使用 XDDP，除非你真的需要极致的性能。</p>
<p>（第二部分完，约 2600 字）</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
