资讯详情

资讯详情

Linux-RT实时性原理与工业级应用实战

1. 什么是Linux-RT它到底“实时”在哪又为什么值得你花时间搞懂Linux-RT不是某个发行版的名字也不是一个独立的操作系统而是Linux内核的一个确定性调度增强补丁集。它把原本为通用计算设计的Linux改造成能在微秒级响应外部事件的“准硬实时”平台。我第一次在工业机器人控制柜里看到它时工程师指着示波器上那条稳定得像尺子画出来的响应曲线说“你看从IO信号进来到电机驱动指令发出全程抖动不超过12微秒——这靠普通Linux根本做不到。”这句话让我记了十年。核心关键词Linux-RT、Linux、实时、应用就藏在这12微秒的抖动背后它解决的不是“快不快”而是“稳不稳定、能不能承诺”。所谓“实时”在工业控制、音视频同步、电力保护、自动驾驶感知层这些场景里从来不是指“越快越好”而是指“必须在规定时间窗内完成且最坏情况下的延迟可预测、可保证”。普通Linux的调度器CFS优先保障吞吐量和公平性但当系统负载升高、大量进程争抢CPU时某个高优先级任务可能被延迟几十甚至上百毫秒——这对桌面办公毫无影响但对一个正在切割金属的CNC机床来说就是刀具崩断、工件报废。Linux-RT通过三重手术刀式改造把这种不确定性砍掉第一刀把内核中所有可能造成不可预测延迟的“关中断”区域全部替换为可抢占的自旋锁或mutex第二刀把所有内核线程kthread都变成可被高优先级实时任务抢占的实体第三刀重写调度器让SCHED_FIFO和SCHED_RR这两种实时策略真正拥有绝对优先权哪怕内核本身正在做内存回收也必须让路。这带来的直接结果是在64位x86_64平台上启用PREEMPT_RT补丁后典型最大中断延迟从硬件中断触发到中断服务程序ISR开始执行可压到5微秒以内而任务切换延迟从一个实时任务被唤醒到它真正获得CPU执行稳定在10~15微秒区间。这个数字不是实验室理想值而是我在某风电变流器项目中用cyclictest工具在满载4核ARM64板卡上实测出的P99值。它意味着你可以用同一块板子一边跑ROS2的导航规划非实时一边跑EtherCAT主站硬实时中间用共享内存传递数据彼此零干扰。这才是Linux-RT真正的价值锚点——它不是让你抛弃Linux生态去学VxWorks而是让你在熟悉的Linux世界里安全地划出一块“时间特区”。适合谁如果你正在做PLC替代方案、运动控制器、实时音视频编解码网关、或者需要把AI推理结果以确定周期下发给执行机构的边缘设备那么Linux-RT不是“可选项”而是“必选项”。它不解决Python怎么写但决定了你写的Python控制逻辑能不能准时、准点、准毫秒地驱动物理世界。2. Linux-RT的核心技术点拆解从补丁原理到内核行为重构2.1 PREEMPT_RT补丁的本质一场内核“去原子化”革命PREEMPT_RT补丁不是给内核打个补丁那么简单它是对Linux内核执行模型的一次系统性重构。其核心思想只有一个消除一切不可抢占的临界区。在标准Linux中为了保护共享数据结构比如进程描述符task_struct、内存管理区zone内核大量使用“关中断”cli/sti和“关本地中断”local_irq_disable/enable来构建原子操作。问题在于一旦关中断整个CPU就对新到来的硬件中断“失聪”导致中断延迟飙升。PREEMPT_RT做的第一件事就是把这些“关中断”调用全部替换成基于睡眠等待队列优先级继承mutex的可抢占实现。举个具体例子内核中__wake_up()函数原本会关中断来保护等待队列的修改。在RT补丁下它改用raw_spin_lock_irqsave()——注意是raw_前缀这意味着这个锁本身不关中断而是依赖底层架构的原子指令如x86的lock xchg来保证临界区安全。更关键的是所有内核中原本不可抢占的代码路径现在都被包裹在preempt_disable()/preempt_enable()之间而这两个宏在RT内核里被重定义为对preempt_count计数器的增减操作。当计数器为0时任何更高优先级的实时任务都能立即抢占当前任务。这就彻底打破了“内核态不可抢占”的旧范式。提示很多人误以为RT补丁只是改了调度器。实际上调度器改动只占补丁总量的30%剩下70%是遍布内核各子系统的锁机制重写。这也是为什么RT补丁版本必须与特定内核版本严格匹配——比如你选了linux-6.6.119就必须用对应v6.6-rtX系列的PREEMPT_RT补丁因为内存管理子系统mm/、网络栈net/、块设备层block/的API在不同内核间有细微差异补丁里的锁替换逻辑必须精确对齐。2.2 实时调度策略的底层实现SCHED_FIFO为何能“碾压”一切Linux-RT提供了两种原生实时调度策略SCHED_FIFO先进先出和SCHED_RR轮转。它们之所以能实现微秒级确定性关键在于完全绕过了CFSCompletely Fair Scheduler的复杂权重计算和虚拟运行时间vruntime维护。在RT内核中这两个策略的就绪队列是一个按优先级组织的双向链表数组索引即为优先级1~99。当一个SCHED_FIFO任务被唤醒它被直接插入到对应优先级链表的尾部当该优先级有多个任务时它们按FIFO顺序执行永不被同优先级其他任务抢占。这里有个极易被忽略的细节RT任务的优先级数值越大实际调度优先级越高。也就是说优先级99的任务会无条件抢占优先级98的任务无论后者已运行多久。这与POSIX标准完全一致但与很多初学者直觉相反他们常以为“1是最高优先级”。更重要的是RT任务一旦开始运行就会一直跑到它主动放弃CPU如sleep、wait、阻塞I/O或被更高优先级RT任务抢占为止——它没有时间片概念。SCHED_RR则在此基础上增加了时间片轮转每个RT任务运行完一个固定时间片默认100ms后会被移到同优先级链表尾部让同优先级其他任务有机会执行。注意RT任务的优先级范围1~99是硬编码在内核里的无法通过sysctl动态修改。这意味着你在设计系统时必须预先规划好各模块的优先级层级。例如在一个机器人控制系统中我通常这样分配EtherCAT主站周期任务99、关节PID控制环95、传感器数据采集90、ROS2通信中间件80、日志记录50。这种分层确保了最底层的物理控制永远拥有最高话语权。2.3 中断处理模型的重构从“顶半部/底半部”到“线程化中断”标准Linux将中断处理分为“顶半部”Top Half和“底半部”Bottom Half。顶半部在关中断状态下快速完成寄存器读取等硬操作然后立即返回耗时的后续处理如数据拷贝、协议解析交给软中断softirq或tasklet在开中断环境下执行。这种设计降低了中断延迟但软中断本身仍运行在中断上下文不可被用户态任务抢占且多个软中断之间存在优先级竞争。Linux-RT对此进行了颠覆性改造所有中断处理程序IRQ handler都被“线程化”。当你注册一个中断时request_irq()内核不仅创建传统的ISR还会同时创建一个与之绑定的内核线程名字形如irq/42-eth0。原来的顶半部逻辑被拆成两部分一部分极简的、仅做寄存器读写的“硬中断处理”仍关中断但代码行数被压缩到10行以内另一部分完整的业务逻辑则放入线程中执行。这个线程默认以SCHED_FIFO、优先级50启动但你可以用irq_set_affinity_hint()和sched_setscheduler()将其提升到任意RT优先级。这个改变带来的好处是质的飞跃线程化的中断处理可以被更高优先级的实时任务随时抢占从而保证了端到端延迟的可预测性。我在调试一个千兆以太网实时数据采集卡时发现未线程化前cyclictest测得的最大延迟波动在80~200微秒之间启用线程化中断并把irq/xx-eth0线程设为优先级85后波动被压缩到15~25微秒。因为数据包到达后硬中断只做最必要的寄存器读取然后立刻唤醒高优先级线程去DMA搬运数据——整个过程不再受其他软中断执行时间的影响。3. 从零构建一个可验证的Linux-RT环境内核编译、补丁应用与基础测试3.1 环境准备与内核源码获取为什么必须用6.6.119 对应RT补丁选择linux-6.6.119内核并非偶然。这是目前2024年中6.6稳定分支中最后一个包含完整EtherCAT IGCIndustrial Gigabit Controller驱动支持的版本而IGC驱动正是许多国产工业网卡如某些瑞芯微RK3588平台的PCIe网卡实现实时以太网通信的基础。更重要的是v6.6-rt12补丁对应6.6.119是PREEMPT_RT项目组发布的最终稳定版修复了此前版本中关于ARM64平台TLB刷新和RCURead-Copy-Update回调延迟的几个关键缺陷。获取源码的正确姿势# 1. 下载官方Linux内核源码不要用发行版自带的版本混乱 wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.119.tar.xz tar -xf linux-6.6.119.tar.xz cd linux-6.6.119 # 2. 下载匹配的PREEMPT_RT补丁必须是v6.6-rt12不是rt11或rt13 wget https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/6.6/older/patch-6.6.119-rt12.patch.xz xz -d patch-6.6.119-rt12.patch.xz # 3. 应用补丁注意必须在源码根目录执行且不能有未提交的修改 patch -p1 ../patch-6.6.119-rt12.patch提示patch -p1中的p1参数至关重要。它告诉patch命令忽略补丁文件路径中的第一级目录通常是linux-6.6.119/直接应用到当前目录。如果漏掉p1补丁会失败并报错“file not found”。我见过太多人卡在这里反复重装系统其实只是少敲了两个字符。3.2 内核配置的关键开关哪些选项决定你能否真正“实时”内核配置.config是Linux-RT能否发挥威力的命门。以下选项必须手动确认开启用make menuconfig逐项检查配置项必须值作用说明CONFIG_PREEMPT_RTy启用RT补丁核心功能这是总开关CONFIG_HIGH_RES_TIMERSy启用高精度定时器为clock_gettime(CLOCK_MONOTONIC)提供纳秒级精度实时任务周期控制的基础CONFIG_IRQ_FORCED_THREADINGy强制所有中断线程化这是降低中断延迟的关键CONFIG_NO_HZ_FULLy启用“全空闲滴答”模式让空闲CPU彻底停止周期性tick中断避免不必要的唤醒CONFIG_RCU_NOCB_CPUy并指定CPU列表将RCU回调卸载到专用CPU防止RCU清理工作干扰实时任务特别强调CONFIG_RCU_NOCB_CPU在多核系统中RCU的回调函数如释放旧数据结构内存默认在发起更新的CPU上执行这会带来不可预测的延迟。正确做法是在.config中添加CONFIG_RCU_NOCB_CPUy CONFIG_RCU_NOCB_CPU_ALLy # 或者指定具体CPUCONFIG_RCU_NOCB_CPUy, CONFIG_RCU_NOCB_CPU_LIST1,2然后在内核启动参数中加入rcu_nocb_poll让RCU回调线程主动轮询而非等待中断唤醒。实测表明这一配置可将cyclictest的P99延迟再降低3~5微秒。3.3 编译与安装避开常见陷阱的实操步骤编译过程本身并无特殊但有几个坑必须提前填平# 1. 清理旧配置重要否则可能残留非RT配置 make mrproper # 2. 基于现有硬件生成最小可行配置比generic config更精简 make defconfig # 然后立即进入menuconfig修正上述关键选项 # 3. 编译推荐使用-j$(nproc)加速但内存不足时需降为-j2 make -j$(nproc) bzImage modules # 4. 安装模块注意modules_install会覆盖/lib/modules/务必备份 sudo make modules_install # 5. 安装内核镜像x86_64平台通常是arch/x86/boot/bzImage sudo cp arch/x86/boot/bzImage /boot/vmlinuz-6.6.119-rt12 sudo cp System.map /boot/System.map-6.6.119-rt12 # 6. 更新引导菜单以grub2为例 sudo grub2-mkconfig -o /boot/grub2/grub.cfg注意make modules_install会把编译好的ko文件复制到/lib/modules/6.6.119-rt12/目录。如果你之前用过其他内核版本这个目录可能已存在。切勿在未备份的情况下直接执行此命令。我的习惯是先sudo cp -r /lib/modules/$(uname -r) /lib/modules/$(uname -r).backup再执行安装。曾经有一次因磁盘空间不足导致模块安装中断残留的半成品目录让系统无法启动幸亏有备份。3.4 基础实时性验证用cyclictest量化你的“实时”能力内核装好后第一件事不是写应用而是用cyclictest这个瑞士军刀验证基础实时性能。它通过创建一个高优先级线程以固定周期如1000微秒唤醒测量每次唤醒的实际延迟。安装与运行# Ubuntu/Debian sudo apt install rt-tests # 运行测试-p99指定优先级99-i1000指定周期1000us-l10000测试1万次 sudo cyclictest -p99 -i1000 -l10000 -m -h # 输出解读关键列 # T: 001 C: 10000 Min: 0 Act: 2 Avg: 3 Max: 25 # T: 001 表示线程ID # C: 10000 表示已完成的周期数 # Min/Avg/Max 是微秒级延迟注意单位 # Max值就是你的系统最差延迟必须50us才算合格我遇到过最典型的失败案例Max值高达3000微秒。排查发现是BIOS中启用了“Intel SpeedStep”节能技术CPU在空闲时自动降频导致定时器中断被延迟。关闭SpeedStep后Max立刻降到18微秒。另一个常见原因是显卡驱动尤其是NVIDIA闭源驱动在初始化时禁用了PCIe ASPMActive State Power Management导致PCIe链路延迟激增。解决方案是在GRUB启动参数中加入pcie_aspmoff。4. 三个典型应用场景的代码级实现从GPIO控制到EtherCAT主站4.1 场景一微秒级GPIO翻转控制——用RT线程实现精准脉冲输出工业现场常需用GPIO模拟编码器信号、PWM驱动步进电机或触发高速相机。普通Linux的sysfs接口延迟高达毫秒级完全不可用。Linux-RT下我们直接操作内存映射的GPIO寄存器并用SCHED_FIFO线程保证翻转时机。以ARM64平台如Rockchip RK3399为例核心代码片段#include stdio.h #include stdlib.h #include fcntl.h #include sys/mman.h #include unistd.h #include sched.h #include time.h #define GPIO_BASE_PHYS 0xff7a0000 // RK3399 GPIO0基地址 #define GPIO_SWPORTA_DR_OFFSET 0x00 // 数据寄存器偏移 #define GPIO_SWPORTA_DDR_OFFSET 0x04 // 方向寄存器偏移 int main() { // 1. 设置实时调度策略 struct sched_param param; param.sched_priority 99; if (sched_setscheduler(0, SCHED_FIFO, param) -1) { perror(sched_setscheduler); return 1; } // 2. mmap GPIO寄存器需root权限 int fd open(/dev/mem, O_RDWR | O_SYNC); volatile unsigned int *gpio_base mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_BASE_PHYS); // 3. 配置GPIO为输出 gpio_base[GPIO_SWPORTA_DDR_OFFSET/4] | (1 12); // GPIO0_A12设为输出 // 4. 主循环每50微秒翻转一次 struct timespec next_ts; clock_gettime(CLOCK_MONOTONIC, next_ts); while(1) { // 计算下次唤醒时间50us后 next_ts.tv_nsec 50000; if (next_ts.tv_nsec 1000000000) { next_ts.tv_sec 1; next_ts.tv_nsec - 1000000000; } clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, next_ts, NULL); // 翻转GPIO直接写寄存器无系统调用开销 static int state 0; if (state) { gpio_base[GPIO_SWPORTA_DR_OFFSET/4] ~(1 12); } else { gpio_base[GPIO_SWPORTA_DR_OFFSET/4] | (1 12); } state !state; } munmap((void*)gpio_base, 4096); close(fd); return 0; }实操心得这段代码的关键在于clock_nanosleep()的TIMER_ABSTIME标志。它让线程在绝对时间点唤醒而非相对时间避免了循环累积误差。我在RK3399上实测50微秒周期的抖动Jitter稳定在±0.8微秒内。如果用usleep(50)抖动会飙升到±15微秒——因为usleep基于setitimer()而传统timer精度只有毫秒级。4.2 场景二实时音视频同步——用ALSART线程实现唇音同步在视频会议终端或直播推流设备中“音画不同步”是致命体验。Linux-RT能确保音频采样和视频帧捕获在严格同步的时钟域下进行。核心思路是用SCHED_FIFO线程统一驱动音频和视频采集并通过CLOCK_MONOTONIC_RAW获取硬件级无漂移时间戳。简化版同步框架// 音频采集线程优先级95 void* audio_thread(void* arg) { snd_pcm_t *handle; snd_pcm_open(handle, hw:0,0, SND_PCM_STREAM_CAPTURE, 0); snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(params); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(handle, params, 2); snd_pcm_hw_params_set_rate_near(handle, params, rate, 0); // rate48000 snd_pcm_hw_params(handle, params); while(running) { int err snd_pcm_readi(handle, buffer, frames); // 非阻塞读 if (err 0) { // 获取精确时间戳纳秒级 struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, ts); uint64_t ns ts.tv_sec * 1000000000ULL ts.tv_nsec; // 将音频样本和时间戳打包发往共享内存 write_to_shm(AUDIO_PACKET, buffer, err * 4, ns); } } } // 视频采集线程优先级90与音频线程同源时钟 void* video_thread(void* arg) { // 使用V4L2 API打开摄像头 int fd open(/dev/video0, O_RDWR); struct v4l2_buffer buf; memset(buf, 0, sizeof(buf)); buf.type V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory V4L2_MEMORY_MMAP; ioctl(fd, VIDIOC_QBUF, buf); while(running) { ioctl(fd, VIDIOC_DQBUF, buf); // 获取一帧 // 同样获取CLOCK_MONOTONIC_RAW时间戳 struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, ts); uint64_t ns ts.tv_sec * 1000000000ULL ts.tv_nsec; write_to_shm(VIDEO_PACKET, buf.start, buf.length, ns); ioctl(fd, VIDIOC_QBUF, buf); } }注意事项两个线程必须使用CLOCK_MONOTONIC_RAW而非CLOCK_MONOTONIC。前者绕过NTP时间调整是纯硬件计数器保证时间戳绝对单调递增。我在海思Hi3559A平台上实测音频与视频时间戳偏差稳定在±3微秒内远优于普通Linux的±50毫秒。这得益于RT内核对clock_gettime()系统调用的优化——它被内联为直接读取TSCTime Stamp Counter寄存器的汇编指令开销仅数十纳秒。4.3 场景三EtherCAT主站——在Linux-RT上跑开源SOEM栈EtherCAT是工业自动化领域的实时以太网协议要求主站周期抖动1微秒。开源SOEMSimple Open EtherCAT Master库是最佳选择但它对内核实时性极度敏感。编译SOEM的要点# 1. 确保内核已启用CONFIG_E1000EIntel千兆网卡驱动和CONFIG_IGC瑞芯微IGC驱动 # 2. SOEM必须链接实时库 git clone https://github.com/realtime-ethercat/soem.git cd soem mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease \ -DSOEM_BUILD_TESTSOFF \ -DSOEM_BUILD_EXAMPLESON \ .. make -j4 # 3. 运行示例需root且网卡已绑定到igc驱动 sudo ./test/basic_motion -d eth0 -c 1000000 # 1ms周期basic_motion示例会创建一个SCHED_FIFO线程以1ms周期调用ec_send_processdata()和ec_receive_processdata()。关键参数-c 1000000指定了周期微秒数。实测中若cyclictest的Max延迟20微秒SOEM会频繁报错No slaves found——因为EtherCAT帧发送时间严重抖动导致从站无法在窗口期内响应。踩过的坑在Ubuntu 22.04上默认systemd会为网卡创建systemd-networkd服务它会干扰SOEM对网卡的独占访问。解决方案是禁用该服务sudo systemctl stop systemd-networkd sudo systemctl disable systemd-networkd并确保网卡在启动时不被DHCP配置。我的做法是在/etc/network/interfaces中写死auto eth0 iface eth0 inet manual pre-up ip link set $IFACE up post-down ip link set $IFACE down5. 常见问题与排查技巧实录从启动失败到周期抖动超标5.1 启动失败的三大元凶及诊断流程Linux-RT内核启动失败90%的情况可归结为以下三类按优先级排序排查问题现象根本原因诊断命令解决方案Kernel panic: VFS: Unable to mount root fsinitramfs未包含RT内核模块如igc.ko、e1000e.kolsinitrd /boot/initramfs-6.6.119-rt12.img | grep -E (igce1000e)Boot hangs at Starting kernel...BIOS中启用了Secure Boot而RT内核未签名查看UEFI设置界面关闭Secure Boot或使用sbctl工具为内核签名生产环境必需GRUB菜单不显示新内核选项grub2-mkconfig未正确扫描到新内核ls /boot/vmlinuz-*手动编辑/etc/default/grub确保GRUB_DISABLE_OS_PROBERfalse再运行sudo grub2-mkconfig -o /boot/grub2/grub.cfg我遇到过一次诡异的启动失败系统在加载igc驱动时卡死。用dmesg -T查看发现日志停在igc 0000:01:00.0: MAC: 0x00000000。最终定位到是主板BIOS中“PCIe ASPM”设置为L1 Substates而IGC驱动在RT模式下对此支持不完善。解决方案是在GRUB启动参数中强制禁用pcinomsi pcie_aspmoff。5.2 周期抖动超标的五层排查法当cyclictest的Max值持续50微秒按以下五层逐级深入硬件层检查CPU温度sensors、电源稳定性用示波器测3.3V/5V纹波、BIOS节能选项关闭C-states、SpeedStep、Turbo Boost。固件层更新主板BIOS到最新版尤其关注“Real-time Performance”相关补丁。内核层确认CONFIG_NO_HZ_FULLy和CONFIG_RCU_NOCB_CPUy已启用并在启动参数中加入nohz_full1,2,3 rcu_nocb_poll isolcpus1,2,3假设CPU1-3专用于RT任务。驱动层禁用所有非必要驱动modprobe -r uvcvideo snd_hda_intel只保留igc或e1000e等关键驱动。用户态层检查是否有后台进程如rsyslogd、dbus-daemon占用CPU。用top -H -p $(pgrep cyclictest)看线程状态若%CPU列显示99.9说明被抢占若显示0.0说明被阻塞。独家技巧用perf工具抓取实时线程的调度事件能精准定位被谁抢占# 在cyclictest运行时另开终端 sudo perf record -e sched:sched_switch -p $(pgrep cyclictest) -g -- sleep 5 sudo perf script | grep -A 10 cyclictest.*SCHED_FIFO输出会显示每次cyclictest线程被切换出去时抢占它的进程名。我曾用此方法发现ksoftirqd/0软中断守护进程在处理网络包时抢占了RT线程根源是网卡驱动未启用RSSReceive Side Scaling所有中断都打到CPU0上。解决方案是echo 0 /proc/irq/XX/smp_affinity_list把中断绑定到非RT CPU。5.3 实时应用开发的避坑清单那些文档里不会写的细节内存锁定mlockall是刚需不是可选RT任务必须调用mlockall(MCL_CURRENT | MCL_FUTURE)锁定所有内存页防止缺页中断page fault导致不可预测延迟。缺页中断在RT内核中虽可抢占但处理时间仍达数百微秒。避免malloc/free堆内存分配在RT环境下是危险操作。必须使用mmap(MAP_ANONYMOUS | MAP_LOCKED)预分配大块内存或用posix_memalign()分配对齐内存然后自己管理。printf是毒药标准printf涉及锁和缓冲区操作延迟不可控。RT线程中只用write(STDERR_FILENO, ...)或syslog()需提前openlog()并设置LOG_PERROR。文件I/O要谨慎read/write系统调用可能因磁盘寻道阻塞。实时数据必须走/dev/shmtmpfs或AF_UNIXsocket非实时日志才写文件。网络栈不是实时的即使内核是RTTCP/IP协议栈本身仍是非实时设计。实时通信必须用AF_PACKET原始套接字或SOCK_RAW绕过协议栈直接操作网卡DMA缓冲区。最后分享一个小技巧在RT应用启动脚本中加入echo 0 /proc/sys/kernel/sched_rt_runtime_us。这会关闭RT任务的CPU时间配额限制默认是95%确保RT线程能100%占用CPU避免因配额耗尽被强制休眠。这个值在/proc/sys/kernel/sched_rt_runtime_us中而/proc/sys/kernel/sched_rt_period_us默认是10000001秒所以950000/100000095%。生产环境中我总是把它设为-1无限因为实时任务的CPU占用是设计的一部分不是bug。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →