<?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%8F%8C%E5%86%85%E6%A0%B8%E6%9E%B6%E6%9E%84/</link>
    <description>Recent content in 双内核架构 on Tech Snippets - 嵌入式技术笔记</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 25 May 2026 19:00:00 +0800</lastBuildDate>
    <atom:link href="https://tech-snippets.xyz/tags/%E5%8F%8C%E5%86%85%E6%A0%B8%E6%9E%B6%E6%9E%84/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Xenomai 实时操作系统深度实战指南：从双内核架构到工业级延迟优化</title>
      <link>https://tech-snippets.xyz/posts/xenomai-real-time-os-comprehensive-guide/</link>
      <pubDate>Mon, 25 May 2026 19:00:00 +0800</pubDate>
      <guid>https://tech-snippets.xyz/posts/xenomai-real-time-os-comprehensive-guide/</guid>
      <description>前言 如果你在工业自动化领域做过嵌入式开发，应该听过这样的抱怨：「Linux 什么都好，就是不够实时」。这句话背后藏着一个非常现实的困境——Linux 生态太强大了，驱动、网络、文件系统、调试工具应有尽有，但它天生就不是为了微秒级确定性设计的。当你的运动控制器需要在 100 µs 内响应编码器中断、当你的机器人关节需要每 1ms 完成一次 PID 闭环计算时，主线 Linux 的调度抖动可能让整个系统失控。
于是就有了三条路：第一条路是彻底放弃 Linux，改用纯 RTOS——VxWorks、QNX、或者 FreeRTOS，但代价是你得放弃整个 Linux 生态；第二条路是 PREEMPT_RT——给 Linux 内核打上实时补丁，这是我们之前详细讨论过的方案；第三条路就是今天的主角：Xenomai——它不走「改造 Linux」的路线，而是走「与 Linux 共存」的双内核架构路线。
我第一次接触 Xenomai 是在一个六轴机械臂项目上。当时客户要求关节控制周期 1ms，最大抖动不能超过 50 µs。我们先用了 PREEMPT_RT，在隔离 CPU、关中断、线程优先级拉满的情况下，最坏情况抖动还是冲到了 120 µs，偶尔还会有 200 µs 的尖刺。后来换成 Xenomai 3 Cobalt 内核，同样的硬件，最坏情况抖动稳定在 15 µs 以内，而且应用层的代码改动量不到 20%。
写这篇文章的目的，不是要争论 Xenomai 和 PREEMPT_RT 谁更好——它们有各自的适用场景。我想做的是把 Xenomai 的技术本质讲清楚，从双内核架构的设计哲学讲起，到实际的环境搭建、应用开发、延迟测量与调优，最后给出我在多个工业项目中验证过的最佳实践。
一、为什么需要 Xenomai？PREEMPT_RT 的极限在哪里？ 在深入 Xenomai 之前，我们得先搞清楚一个问题：既然 PREEMPT_RT 能让 Linux 变成实时系统，为什么还需要 Xenomai？
1.1 PREEMPT_RT 的本质：把 Linux 尽量改得「更实时」 PREEMPT_RT 的核心思路是最大化 Linux 内核的可抢占性：</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>如果你在工业自动化领域做过嵌入式开发，应该听过这样的抱怨：「Linux 什么都好，就是不够实时」。这句话背后藏着一个非常现实的困境——Linux 生态太强大了，驱动、网络、文件系统、调试工具应有尽有，但它天生就不是为了微秒级确定性设计的。当你的运动控制器需要在 100 µs 内响应编码器中断、当你的机器人关节需要每 1ms 完成一次 PID 闭环计算时，主线 Linux 的调度抖动可能让整个系统失控。</p>
<p>于是就有了三条路：第一条路是彻底放弃 Linux，改用纯 RTOS——VxWorks、QNX、或者 FreeRTOS，但代价是你得放弃整个 Linux 生态；第二条路是 PREEMPT_RT——给 Linux 内核打上实时补丁，这是我们之前详细讨论过的方案；第三条路就是今天的主角：<strong>Xenomai</strong>——它不走「改造 Linux」的路线，而是走「与 Linux 共存」的双内核架构路线。</p>
<p>我第一次接触 Xenomai 是在一个六轴机械臂项目上。当时客户要求关节控制周期 1ms，最大抖动不能超过 50 µs。我们先用了 PREEMPT_RT，在隔离 CPU、关中断、线程优先级拉满的情况下，最坏情况抖动还是冲到了 120 µs，偶尔还会有 200 µs 的尖刺。后来换成 Xenomai 3 Cobalt 内核，同样的硬件，最坏情况抖动稳定在 15 µs 以内，而且应用层的代码改动量不到 20%。</p>
<p>写这篇文章的目的，不是要争论 Xenomai 和 PREEMPT_RT 谁更好——它们有各自的适用场景。我想做的是把 Xenomai 的技术本质讲清楚，从双内核架构的设计哲学讲起，到实际的环境搭建、应用开发、延迟测量与调优，最后给出我在多个工业项目中验证过的最佳实践。</p>
<h2 id="一为什么需要-xenomaipreempt_rt-的极限在哪里">一、为什么需要 Xenomai？PREEMPT_RT 的极限在哪里？</h2>
<p>在深入 Xenomai 之前，我们得先搞清楚一个问题：既然 PREEMPT_RT 能让 Linux 变成实时系统，为什么还需要 Xenomai？</p>
<h3 id="11-preempt_rt-的本质把-linux-尽量改得更实时">1.1 PREEMPT_RT 的本质：把 Linux 尽量改得「更实时」</h3>
<p>PREEMPT_RT 的核心思路是<strong>最大化 Linux 内核的可抢占性</strong>：</p>
<ul>
<li>把所有 spinlock 改成可抢占的 mutex</li>
<li>把中断处理线程化，让高优先级任务可以抢占中断</li>
<li>引入优先级继承，解决优先级反转问题</li>
<li>优化调度器，减少调度延迟</li>
</ul>
<p>但不管怎么改，PREEMPT_RT 依然是「Linux 内核的一部分」。它跑在同一个地址空间，共享同一个调度器，使用同一个内存管理子系统。这意味着它永远摆脱不了 Linux 的一些结构性开销：</p>
<ul>
<li><strong>页错误处理</strong>：即使是实时线程，访问未映射的内存页依然会触发缺页异常，这可能需要几百微秒甚至几毫秒</li>
<li><strong>RCU 回调</strong>：虽然有 RCU priority boosting，但极端情况下依然可能造成阻塞</li>
<li><strong>内存回收</strong>：即使是 mlockall 锁定的内存，在极端内存压力下依然可能有意外</li>
<li><strong>各种子系统的不可预知性</strong>：网络、存储、驱动层都可能引入意料之外的延迟</li>
</ul>
<h3 id="12-xenomai-的哲学让实时内核和-linux-内核平起平坐">1.2 Xenomai 的哲学：让实时内核和 Linux 内核平起平坐</h3>
<p>Xenomai 走了一条完全不同的路——它不是「给 Linux 打补丁」，而是<strong>在硬件之上同时运行两个内核</strong>：</p>
<ul>
<li><strong>Cobalt 内核</strong>（实时内核）：专门处理实时任务，极简设计，只有几千行代码，没有复杂的内存管理和调度开销</li>
<li><strong>Linux 内核</strong>（通用内核）：处理所有非实时任务，完整的 Linux 生态</li>
</ul>
<p>这两个内核通过一个叫做 <strong>IPE（Inter-Pipeline Execution）</strong> 的机制协调工作。当中断到来时，Cobalt 内核首先检查这个中断是否是实时中断。如果是，直接由实时内核处理；如果不是，再转发给 Linux 内核。</p>
<p>关键在于：<strong>Cobalt 内核永远不会被 Linux 内核抢占</strong>。不管 Linux 里面在干什么——不管是在做大规模内存回收，还是在处理网络拥塞，还是在触发 kernel panic——实时任务的调度都不受影响。</p>
<h3 id="13-延迟数据对比preempt_rt-vs-xenomai">1.3 延迟数据对比：PREEMPT_RT vs Xenomai</h3>
<p>这是在同一台硬件（i.MX6 Quad，1GHz）上测试的 1ms 周期任务延迟数据：</p>
<table>
<thead>
<tr>
<th>指标</th>
<th>PREEMPT_RT（优化后）</th>
<th>Xenomai 3 Cobalt</th>
</tr>
</thead>
<tbody>
<tr>
<td>平均延迟</td>
<td>8 µs</td>
<td>5 µs</td>
</tr>
<tr>
<td>99% 延迟</td>
<td>35 µs</td>
<td>10 µs</td>
</tr>
<tr>
<td>最坏情况延迟</td>
<td>120 µs</td>
<td>14 µs</td>
</tr>
<tr>
<td>运行时间</td>
<td>24 小时</td>
<td>24 小时</td>
</tr>
</tbody>
</table>
<p>可以看到，平均延迟差距不大，但在最坏情况延迟上，Xenomai 的优势是压倒性的。这就是为什么在工业控制、机器人、运动控制这些对最坏情况延迟有严格要求的领域，Xenomai 依然是首选方案。</p>
<h3 id="14-什么时候该用-xenomai什么时候该用-preempt_rt">1.4 什么时候该用 Xenomai，什么时候该用 PREEMPT_RT？</h3>
<p><strong>选择 Xenomai 的场景：</strong></p>
<ul>
<li>最坏情况延迟要求 &lt; 50 µs</li>
<li>周期任务频率 &gt; 1kHz</li>
<li>系统需要长时间（数月甚至数年）稳定运行，不能有任何延迟尖刺</li>
<li>可以接受一定程度的应用层代码修改</li>
</ul>
<p><strong>选择 PREEMPT_RT 的场景：</strong></p>
<ul>
<li>延迟要求在几百微秒量级即可</li>
<li>希望应用代码 100% 兼容标准 POSIX</li>
<li>需要充分利用 Linux 生态的所有功能</li>
<li>团队没有实时系统专业经验</li>
</ul>
<h2 id="二xenomai-双内核架构深度解析">二、Xenomai 双内核架构深度解析</h2>
<p>理解 Xenomai 的第一步，是搞清楚它的架构到底是怎么工作的。</p>
<h3 id="21-整体架构概览">2.1 整体架构概览</h3>
<p><img alt="Xenomai 双内核架构示意图" loading="lazy" src="/images/posts/2026/05/xenomai-dual-kernel-architecture.svg"></p>
<p>从下到上，Xenomai 的架构分为四层：</p>
<p><strong>第一层：硬件层</strong></p>
<ul>
<li>CPU、中断控制器、定时器</li>
<li>Cobalt 和 Linux 共享同一套硬件</li>
</ul>
<p><strong>第二层：Dovetail 层</strong></p>
<ul>
<li>这是 Xenomai 3.1+ 引入的中断流水线机制</li>
<li>取代了之前的 Adeos（Adaptive Domain Environment for Operating Systems）</li>
<li>负责中断分发和内核间的协调</li>
</ul>
<p><strong>第三层：双内核层</strong></p>
<ul>
<li><strong>Cobalt 内核</strong>：实时内核，调度实时线程</li>
<li><strong>Linux 内核</strong>：通用内核，调度普通线程</li>
</ul>
<p><strong>第四层：应用层</strong></p>
<ul>
<li><strong>实时应用</strong>：链接 libcobalt，调用 Xenomai 原生 API 或 POSIX API</li>
<li><strong>普通应用</strong>：标准 Linux 应用</li>
</ul>
<h3 id="22-dovetail-中断流水线是如何工作的">2.2 Dovetail 中断流水线是如何工作的？</h3>
<p>Dovetail 是整个双内核架构的核心。它不是一个 hypervisor，也不是一个虚拟机。它是一个非常轻量级的中断管道（interrupt pipeline）。</p>
<p>当中断从硬件产生时，它首先到达 Dovetail，然后 Dovetail 按照注册顺序把中断分发给各个内核：</p>
<pre tabindex="0"><code>硬件中断 → Dovetail → Cobalt 内核（先检查）
                      → 如果是实时中断，处理，不转发给 Linux
                      → 如果不是实时中断，转发给 Linux 内核
</code></pre><p>这个顺序是关键——Cobalt 永远排在 Linux 前面。所以实时中断永远会被优先处理，Linux 只能拿到 Cobalt 不要的中断。</p>
<p>这就解释了为什么 Xenomai 的延迟那么稳定——不管 Linux 里面在干什么，实时中断永远第一时间被 Cobalt 处理。</p>
<h3 id="23-cobalt-调度器为什么它这么快">2.3 Cobalt 调度器：为什么它这么快？</h3>
<p>Cobalt 调度器和 Linux CFS 调度器相比，简直简单到了极致：</p>
<ul>
<li>只有优先级调度，没有 CFS 的公平调度</li>
<li>每个优先级一个链表，总共 256 个优先级（0-255，数值越大优先级越高）</li>
<li>调度时直接找最高优先级的非空链表，取第一个任务</li>
<li>整个调度过程是 O(1) 的时间复杂度</li>
<li>没有负载均衡，没有组调度，没有各种复杂的统计</li>
</ul>
<p>而且 Cobalt 调度器是<strong>完全不可抢占的</strong>吗？不，它是<strong>可抢占的，但只被更高优先级的任务抢占</strong>。一旦一个实时任务开始运行，它会一直运行直到：</p>
<ol>
<li>它主动让出 CPU</li>
<li>它调用了阻塞的系统调用</li>
<li>有更高优先级的任务就绪</li>
</ol>
<p>这种简单粗暴的设计，换来的是确定性。</p>
<h3 id="24-内存模型实时任务的内存是怎么管理的">2.4 内存模型：实时任务的内存是怎么管理的？</h3>
<p>这是 Xenomai 另一个聪明的设计：实时任务的内存不是由 Cobalt 管理的，而是<strong>由 Linux 预先分配好，然后锁定在物理内存中</strong>。</p>
<p>具体流程是：</p>
<ol>
<li>实时应用在 Linux 上下文中分配内存（malloc/mmap）</li>
<li>调用 mlockall() 把所有内存锁定，防止换出</li>
<li>切换到 Cobalt 上下文执行</li>
<li>执行过程中，Cobalt 不会做任何内存分配或释放</li>
</ol>
<p>换句话说，Cobalt 内核本身几乎不做内存管理。所有复杂的内存管理工作都交给 Linux 在非实时阶段完成。实时阶段只使用预先锁定好的内存，完全避免了页错误和内存回收的开销。</p>
<h3 id="25-两个内核如何通信">2.5 两个内核如何通信？</h3>
<p>Cobalt 和 Linux 之间需要通信，比如实时任务需要打印日志、需要读写文件、需要发送网络数据包。</p>
<p>Xenomai 提供了几种通信机制：</p>
<p><strong>1. 代理系统调用（Proxy syscalls）</strong></p>
<ul>
<li>实时任务调用 Linux 系统调用时，会通过代理转发给 Linux 执行</li>
<li>这个过程是异步的，不会阻塞实时任务</li>
<li>但代价是有一定的延迟，所以不建议在实时路径中频繁使用</li>
</ul>
<p><strong>2. 共享内存（Shared memory）</strong></p>
<ul>
<li>Cobalt 和 Linux 共享同一块物理内存</li>
<li>可以通过共享内存交换大量数据</li>
<li>需要自己实现同步机制</li>
</ul>
<p><strong>3. XDDP（Xenomai Data Distribution Protocol）</strong></p>
<ul>
<li>Xenomai 提供的实时套接字机制</li>
<li>支持实时任务之间、实时任务和 Linux 任务之间的通信</li>
<li>延迟低，确定性好</li>
</ul>
<h2 id="三环境搭建从零开始部署-xenomai-3">三、环境搭建：从零开始部署 Xenomai 3</h2>
<p>现在我们开始实战，第一步是搭建 Xenomai 开发环境。</p>
<h3 id="31-硬件选择">3.1 硬件选择</h3>
<p>Xenomai 支持的架构非常广泛：x86_64、ARM32、ARM64、PowerPC 等等。但要获得最好的实时性能，你需要注意：</p>
<p><strong>推荐的开发板：</strong></p>
<ul>
<li>Raspberry Pi 4（ARM64）：性价比高，社区支持好，实测最坏延迟 ~25 µs</li>
<li>BeagleBone Black（ARM32）：经典实时平台，最坏延迟 ~15 µs</li>
<li>i.MX6 系列：工业级，最坏延迟 ~10 µs</li>
<li>x86_64 工控机：带 TSC 定时器，最坏延迟 ~5 µs</li>
</ul>
<p><strong>要避免的硬件：</strong></p>
<ul>
<li>任何带 SMM（System Management Mode）的 x86 平台：SMM 中断对 OS 不可见，会造成几百微秒的不可控延迟</li>
<li>频率动态调节过于激进的 ARM 平台：建议关闭 DVFS，固定 CPU 频率</li>
<li>没有高精度定时器（HPET）的平台</li>
</ul>
<h3 id="32-内核编译流程">3.2 内核编译流程</h3>
<p>我们以 Raspberry Pi 4 为例，演示完整的 Xenomai 3.2.x + Linux 6.1 内核编译流程。</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">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"># 下载 Linux 内核</span>
</span></span><span class="line"><span class="cl">git clone https://github.com/raspberrypi/linux.git --depth <span class="m">1</span> --branch rpi-6.1.y
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 Xenomai 3</span>
</span></span><span class="line"><span class="cl">git clone https://gitlab.denx.de/Xenomai/xenomai.git --depth <span class="m">1</span> --branch v3.2.x
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 Dovetail 补丁（对应内核版本）</span>
</span></span><span class="line"><span class="cl">wget https://evlproject.org/download/patches/dovetail/dovetail-linux-6.1.y-arm64.patch
</span></span></code></pre></div><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="nb">cd</span> linux
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 应用 Dovetail 补丁</span>
</span></span><span class="line"><span class="cl">patch -p1 &lt; ../dovetail-linux-6.1.y-arm64.patch
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 应用 Xenomai Cobalt 补丁</span>
</span></span><span class="line"><span class="cl">../xenomai/scripts/prepare-kernel.sh --arch<span class="o">=</span>arm64
</span></span></code></pre></div><p>这个 <code>prepare-kernel.sh</code> 脚本是 Xenomai 提供的自动化工具，它会自动把 Cobalt 内核的代码合入 Linux 源码树。</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">make bcm2711_defconfig
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 配置 Xenomai 相关选项</span>
</span></span><span class="line"><span class="cl">make menuconfig
</span></span></code></pre></div><p>在 menuconfig 中需要开启这些选项：</p>
<pre tabindex="0"><code># Dovetail 支持
General setup → Interrupt pipeline [Y]

# Cobalt 内核
Xenomai → Cobalt real-time core [Y]
Xenomai → Cobalt → Real-time core features → Enable priority inheritance [Y]
Xenomai → Cobalt → Real-time core features → Enable shared heaps [Y]

# 关闭不需要的功能，减少延迟
Kernel hacking → KGDB: kernel debugger [N]
Kernel hacking → Tracers [N]
Power management → CPU Frequency scaling [N]  # 或者固定频率
Power management → CPU idle → CPU idle PM support [N]
</code></pre><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">make -j<span class="k">$(</span>nproc<span class="k">)</span> Image modules dtbs
</span></span></code></pre></div><h3 id="33-安装-xenomai-用户态库">3.3 安装 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
</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">./scripts/bootstrap
</span></span><span class="line"><span class="cl">./configure --prefix<span class="o">=</span>/usr/xenomai --with-core<span class="o">=</span>cobalt --enable-smp
</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 -j<span class="k">$(</span>nproc<span class="k">)</span>
</span></span><span class="line"><span class="cl">make 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"><span class="nb">echo</span> <span class="s1">&#39;export PATH=$PATH:/usr/xenomai/bin&#39;</span> &gt;&gt; /etc/profile
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/xenomai/lib&#39;</span> &gt;&gt; /etc/profile
</span></span></code></pre></div><h3 id="34-验证安装">3.4 验证安装</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="c1"># 检查内核版本</span>
</span></span><span class="line"><span class="cl">uname -a
</span></span><span class="line"><span class="cl">
</span></span><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 cobalt
</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 -s <span class="m">1000</span>
</span></span></code></pre></div><p>如果看到类似下面的输出，说明安装成功：</p>
<pre tabindex="0"><code>== Sampling period: 1000 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|      2.845|      5.217|     13.562|       0|     0|      2.845|     13.562
</code></pre><p>这里的 <code>lat max</code> 只有 13.562 µs，这就是 Xenomai 的威力。</p>
<h2 id="四xenomai-应用开发从-hello-world-到实时任务">四、Xenomai 应用开发：从 Hello World 到实时任务</h2>
<p>现在我们开始学习 Xenomai 应用开发。Xenomai 提供了两套 API：</p>
<ol>
<li><strong>原生 API（Alchemy API）</strong>：功能最强大，性能最好，但不是 POSIX 标准</li>
<li><strong>POSIX 兼容层 API</strong>：和标准 POSIX pthread 几乎一样，代码可移植性好</li>
</ol>
<p>对于新项目，我推荐直接使用 POSIX 兼容层，因为学习成本低，代码可移植。</p>
<h3 id="41-hello-world第一个实时任务">4.1 Hello World：第一个实时任务</h3>
<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;string.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;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">#include</span> <span class="cpf">&lt;xenomai/init.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 PRIORITY 99
</span></span></span><span class="line"><span class="cl"><span class="cp">#define STACK_SIZE 8192
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">realtime_task</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">arg</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="k">struct</span> <span class="n">sched_param</span> <span class="n">param</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="n">param</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="n">ret</span> <span class="o">=</span> <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 class="k">if</span> <span class="p">(</span><span class="n">ret</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">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;pthread_setschedparam 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="n">ret</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="nf">printf</span><span class="p">(</span><span class="s">&#34;实时线程开始运行，优先级 = %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">PRIORITY</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="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">printf</span><span class="p">(</span><span class="s">&#34;Hello from Xenomai real-time thread!</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">// 注意：不要在实时循环里用 printf，这只是演示
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        <span class="c1">// printf 会触发 Linux 系统调用，造成不确定延迟
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>        
</span></span><span class="line"><span class="cl">        <span class="nf">sleep</span><span class="p">(</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="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="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></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <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">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">// 1. 锁定所有内存，防止页错误
</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">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></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">ret</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;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><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 2. 初始化 Xenomai
</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">xenomai_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">argc</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">argv</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">!=</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;xenomai_init 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="n">ret</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">// 3. 创建实时线程
</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">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="kr">thread</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">realtime_task</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">!=</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;pthread_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="n">ret</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="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 hello_xenomai hello_xenomai.c <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    <span class="k">$(</span>/usr/xenomai/bin/xeno-config --skin<span class="o">=</span>posix --cflags --ldflags<span class="k">)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>    -lpthread
</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">./hello_xenomai
</span></span></code></pre></div><h3 id="42-关键的初始化步骤详解">4.2 关键的初始化步骤详解</h3>
<p>上面的代码里，有几个步骤是<strong>绝对不能省略</strong>的：</p>
<p><strong>1. mlockall(MCL_CURRENT | MCL_FUTURE)</strong></p>
<p>这是最重要的一步。它告诉内核：把当前进程所有的内存都锁定在物理内存中，不要换出到 swap，而且将来分配的内存也要自动锁定。</p>
<p>如果省略这一步，你的实时线程可能在运行中遇到页错误，触发 Linux 缺页异常处理，造成几百微秒甚至几毫秒的延迟。</p>
<p><strong>2. xenomai_init(&amp;argc, &amp;argv)</strong></p>
<p>这一步初始化 Xenomai 运行时环境。它会：</p>
<ul>
<li>打开 /dev/xenomai/cobalt 设备文件</li>
<li>注册线程到 Cobalt 内核</li>
<li>设置信号处理函数</li>
</ul>
<p>如果省略这一步，你的线程依然可以运行，但它运行在 Linux 上下文，而不是 Cobalt 上下文。这是新手最容易犯的错误——写了代码，加了优先级，但忘了调用 xenomai_init，结果根本没跑在实时内核上。</p>
<p><strong>3. pthread_setschedparam + SCHED_FIFO</strong></p>
<p>设置线程调度策略为 SCHED_FIFO（实时调度），优先级 99。Xenomai 的优先级范围是 1-99，数值越大优先级越高。</p>
<p>注意：Xenomai 的优先级是<strong>独立于 Linux 优先级</strong>的。一个优先级为 1 的 Xenomai 实时线程，依然可以抢占任何 Linux 线程（包括 Linux 的 idle 线程）。</p>
<h3 id="43-周期性实时任务工业控制的标准模式">4.3 周期性实时任务：工业控制的标准模式</h3>
<p>在工业控制中，90% 的实时任务都是周期性的——每 1ms 读一次传感器，每 2ms 计算一次 PID，每 5ms 输出一次控制量。</p>
<p>Xenomai 提供了专门的周期性定时器机制：</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;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;sys/mman.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;xenomai/init.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 90
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">periodic_task</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">arg</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="k">struct</span> <span class="n">sched_param</span> <span class="n">param</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</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="n">param</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">// 获取当前时间
</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_REALTIME</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">next</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="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="n">next</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</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</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</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></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_REALTIME</span><span class="p">,</span> <span class="n">TIMER_ABSTIME</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">next</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="n">count</span><span class="o">++</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">// 读取传感器、计算 PID、输出控制信号
</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="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="c1">// 每秒打印一次统计信息
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;运行了 %llu 个周期</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></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="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></code></pre></div><p>使用绝对时间休眠（<code>TIMER_ABSTIME</code>）是非常重要的细节。如果使用相对时间休眠，每次休眠的误差会累积，最终周期会漂移。使用绝对时间可以保证精确的周期性。</p>
<h3 id="44-xenomai-同步原语mutex-和-semaphore">4.4 Xenomai 同步原语：Mutex 和 Semaphore</h3>
<p>和标准 POSIX 一样，Xenomai 提供了 Mutex（互斥锁）和 Semaphore（信号量）用于线程间同步。</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">// Mutex 示例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><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">mutex_attr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 初始化 Mutex 属性
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">pthread_mutexattr_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex_attr</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">pthread_mutexattr_setprotocol</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex_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></span><span class="line"><span class="cl"><span class="c1">// 初始化 Mutex
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><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">mutex_attr</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="nf">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</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">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>
</span></span></code></pre></div><p><strong>重要提示</strong>：一定要开启优先级继承（<code>PTHREAD_PRIO_INHERIT</code>）。如果不开启，低优先级线程持有锁时，中间优先级的线程可能抢占低优先级线程，导致高优先级线程等待锁的时间无限延长——这就是经典的<strong>优先级反转问题</strong>。</p>
<h3 id="45-实时任务和-linux-任务通信xddp">4.5 实时任务和 Linux 任务通信：XDDP</h3>
<p>实时任务经常需要和非实时的 Linux 任务交换数据——比如实时线程采集的数据要传给 Linux 线程保存到文件，或者 Linux 线程接收的配置参数要传给实时线程。</p>
<p>Xenomai 提供了 XDDP（Xenomai Data Distribution Protocol）机制：</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="cp">#include</span> <span class="cpf">&lt;rtdm/xddp.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="kt">int</span> <span class="n">sk</span> <span class="o">=</span> <span class="nf">socket</span><span class="p">(</span><span class="n">AF_RTIPC</span><span class="p">,</span> <span class="n">SOCK_DGRAM</span><span class="p">,</span> <span class="n">IPCPROTO_XDDP</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sockaddr_xddp</span> <span class="n">addr</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">sxddp_family</span> <span class="o">=</span> <span class="n">AF_RTIPC</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">sxddp_port</span> <span class="o">=</span> <span class="mi">1234</span><span class="p">,</span>  <span class="c1">// 端口号
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="p">.</span><span class="n">sxddp_label</span> <span class="o">=</span> <span class="s">&#34;realtime_sender&#34;</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">bind</span><span class="p">(</span><span class="n">sk</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">addr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">addr</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="nf">sendto</span><span class="p">(</span><span class="n">sk</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">data_size</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</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">// Linux 端接收数据
</span></span></span><span class="line"><span class="cl"><span class="c1">// 使用标准的 socket API，连接到同一个端口
</span></span></span><span class="line"><span class="cl"><span class="c1">// 注意：Linux 端使用的是普通 socket，不是 Xenomai socket
</span></span></span></code></pre></div><p>XDDP 的优点是：</p>
<ul>
<li>实时端发送完全是非阻塞的，延迟极低</li>
<li>支持大数据传输（最高 64KB 缓冲区）</li>
<li>可以在中断上下文、线程上下文使用</li>
</ul>
<p>（第二部分完，约2100字）</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
