菜单

PREEMPT_RT 实时应用程序教程

PREEMPT_RT 实时应用程序教程

这些教程通常需要一个终端用于执行教程应用程序,至少一个额外的终端用于执行各种影响应用程序行为的压力测试,或用于监控以捕获其操作的统计信息。最好通过 SSH 远程访问执行教程的系统,以避免桌面 GUI 中断影响测量结果(非Xenomai内核)。

教程包括:

  • CPU 核心关联(CPU Core Affinity):在一个隔离的核心上执行,以最小化系统和其他应用程序的影响
  • 内存锁定(Memory Locking):锁定内存以避免页面错误,页面错误会导致中断并影响确定性
  • 实时优先级(Real-Time Priority):使用 RT 优先级线程执行应用程序,以避免抢占

CPU亲和性

  • 使用代码设置CPU亲和性

    c 复制代码
      #include <pthread.h>
      #include <sched.h>
      #include <stdio.h>
    
      int main() {
          pthread_t thread = pthread_self(); // 获取当前线程
          cpu_set_t cpµset;                  // 定义 CPU 集合
          int cpu = 2;                       // 要绑定的 CPU 核心
    
          CPU_ZERO(&cpµset);    // 清除 CPU 集合
          CPU_SET(cpu, &cpµset); // 将 CPU 2 添加到集合中
    
          // 设置线程的 CPU 亲和性
          if (pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpµset) != 0) {
              perror("设置 CPU 亲和性失败");
              return 1;
          }
    
          printf("线程已成功绑定到 CPU %d。\n", cpu);
    
          return 0;
      }
  • 使用命令行设置CPU亲和性

    shell 复制代码
    # 可以启动一个程序并将其绑定到特定的 CPU(比如 CPU 0 和 CPU 1)
    sudo taskset -c 0,1 my_program

在非隔离的CPU上测试

开始在CPU2上执行应用程序(非隔离)

shell 复制代码
latency -c2 -t0 -p 100 -P 99 -h

平均值为 30µs

在隔离的CPU上测试

开始在CPU1上执行应用程序(隔离)

shell 复制代码
latency -c1 -t0 -p 100 -P 99 -h

平均值为 10µs


内存锁定教程

页面错误(Page faults)会对确定性产生负面影响。内存锁定可以防止应用程序中大部分甚至全部页面错误的发生。

  • 使用代码设置内存锁定(mlockall)
    c 复制代码
      #include <stdio.h>
      #include <stdlib.h>
      #include <sys/mman.h>  // 包含 mlockall 函数的头文件
      #include <unistd.h>    // 包含 sleep 函数的头文件
    
      int main() {
          // 使用 mlockall 锁定进程的所有内存到物理内存中
          // MCL_CURRENT: 锁定当前内存页
          // MCL_FUTURE: 锁定未来分配的内存页
          if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
              perror("内存锁定失败");
              return 1;
          }
    
          printf("内存已锁定,防止交换到磁盘。\n");
    
          // 模拟程序运行,期间内存保持锁定
          for (int i = 0; i < 10; i++) {
              printf("程序运行中...\n");
              sleep(1);  // 休眠 1 秒
          }
    
          // 解除内存锁定
          if (munlockall() != 0) {
              perror("解除内存锁定失败");
              return 1;
          }
    
          printf("内存锁定已解除。\n");
          return 0;
      }

可以通过健康监测工具健康进程的Page faults次数

shell 复制代码
sudo sjournal_run 1h

实时线程优先级

实时应用程序会抢占其他非实时的应用程序。优先级参数设置执行工作负载的线程优先级。当此参数被省略或设置为零时,线程不是实时的。将其设置为99可确保RT执行。

使用代码设置为实时线程优先级

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>

// 线程函数
void* thread_func(void* arg) {
    while (1) {
        // 模拟一些工作
        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t thread;
    struct sched_param param;
    int policy = SCHED_FIFO;  // 使用 FIFO 实时调度策略
    int max_priority, min_priority;

    // 创建线程
    if (pthread_create(&thread, NULL, thread_func, NULL) != 0) {
        perror("无法创建线程");
        return 1;
    }

    // 获取 SCHED_FIFO 策略的最大和最小优先级
    max_priority = sched_get_priority_max(SCHED_FIFO);
    min_priority = sched_get_priority_min(SCHED_FIFO);

    printf("SCHED_FIFO 最大优先级: %d, 最小优先级: %d\n", max_priority, min_priority);

    // 设置线程的优先级(选择一个合适的值,如最大优先级)
    param.sched_priority = max_priority;

    // 设置线程的调度策略和优先级
    if (pthread_setschedparam(thread, policy, &param) != 0) {
        perror("无法设置线程优先级");
        return 1;
    }

    printf("线程已设置为实时优先级 (SCHED_FIFO, 优先级: %d)\n", param.sched_priority);

    // 等待线程结束
    pthread_join(thread, NULL);

    return 0;
}

使用命令行设置线程为实时线程

shell 复制代码
# 将正在运行的进程转换为实时调度策略
sudo chrt -f 99 <priority> <pid>

# 以实时调度策略启动新进程
sudo chrt -f 99 <priority> <command>

使用下面的命令查看设置是否成功

shell 复制代码
chrt -p <pid>
最近修改: 2025-08-19