Linux中的实时线程

目录

  • 一、Linux线程调度策略
  • 二、SCHED_RR 为什么比 SCHED_OTHER 要实时呢
  • 三、如何使用线程调度相关API
    • 1、相关API介绍
    • 2、示例代码

一、Linux线程调度策略

  在 Linux 中,调度策略(scheduling policy)是操作系统用来决定进程或线程调度顺序的算法。在 <sched.h> 头文件中定义了几种调度策略,其中包括以下三种常见的调度策略:

#define SCHED_OTHER		0
#define SCHED_FIFO		1
#define SCHED_RR		2
  1. SCHED_OTHER:又称为 CFS(Completely Fair Scheduler),是 Linux 默认的调度策略。它基于时间片(time-slice)的概念,使用公平调度算法,以尽量保证所有进程或线程公平地分享 CPU 时间。对于大多数普通应用程序来说,默认的 SCHED_OTHER 调度策略已经足够。

  2. SCHED_FIFO:先进先出调度策略,也称为实时(real-time)调度策略之一。按照任务到达顺序依次运行,直到任务主动释放 CPU 或者被更高优先级的任务抢占。

  3. SCHED_RR:轮转调度策略,也是一种实时调度策略。每个任务都按照一定时间片轮流使用 CPU,当时间片用完后,任务会被挂起并被放置到队列的末尾,然后下一个任务开始执行。SCHED_RR 调度策略允许设置不同的任务优先级,优先级高的任务会在优先级低的任务之前执行。

  这些调度策略可以通过 sched_setscheduler 函数来设置进程或线程的调度策略。以下是一个示例,展示了如何使用 sched_setscheduler 函数将进程的调度策略设置为 SCHED_FIFO

#include <stdio.h>
#include <sched.h>
#include <unistd.h>int main() {struct sched_param param;// 设置进程的调度策略为 SCHED_FIFOif (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {perror("sched_setscheduler");return 1;}// 获取当前进程的调度策略和优先级int policy = sched_getscheduler(0);if (policy == -1) {perror("sched_getscheduler");return 1;}int priority = sched_get_priority_max(policy);if (priority == -1) {perror("sched_get_priority_max");return 1;}printf("调度策略: %d,优先级范围: 1 - %d\n", policy, priority);return 0;
}

  在上述示例中,通过调用 sched_setscheduler 函数将当前进程的调度策略设置为 SCHED_FIFO。然后,通过调用 sched_getschedulersched_get_priority_max 函数获取当前进程的调度策略和允许的最高优先级。

二、SCHED_RR 为什么比 SCHED_OTHER 要实时呢

  SCHED_RR 被称为轮转调度(Round-Robin Scheduling)策略,它在 Linux 中被认为是一种实时调度策略。相比于默认调度策略 SCHED_OTHERSCHED_RR 具有实时性的原因有以下几点:

  1. 时间片轮转:SCHED_RR 使用时间片轮转的方式进行调度。每个任务被分配一个时间片,在时间片内运行,当时间片用完时,操作系统会自动切换到下一个任务。这种轮转的调度方式使得每个任务都能按照一定时间间隔获得 CPU 的使用权,提高了实时性。

  2. 优先级调度:SCHED_RR 允许为不同任务设置不同的优先级。优先级高的任务在时间片内先于优先级低的任务执行。这样可以确保优先级高的实时任务能够及时得到 CPU 的调度,并避免优先级低的任务长时间占用 CPU。

  3. 抢占能力:SCHED_RR 具有抢占能力,即优先级更高的任务可以抢占优先级低的任务,即使后者还没有用完时间片。这样,当出现具有更高优先级的实时任务时,操作系统可以及时地将 CPU 资源分配给它,从而提高实时性。

  总体而言,相比于默认的 SCHED_OTHER 调度策略,SCHED_RR 具有更好的实时性能。它为实时应用程序提供了更精确的任务调度控制和保证,使得这些任务能够满足对响应性和实时性要求更高的应用场景。

  需要注意的是,SCHED_RR 并不是 Linux 中唯一的实时调度策略,还有其他实时调度策略如 SCHED_FIFO 可供选择,具体的选择要根据应用需求和系统的实时性要求进行合理的决策。

三、如何使用线程调度相关API

1、相关API介绍

pthread_attr_init
  其是一个 Linux 线程 API 函数,用于初始化线程属性对象。在使用线程属性对象之前,必须先调用该函数进行初始化。

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);`attr` 参数是指向线程属性对象的指针,该指针指向的内存空间将被用于存储线程属性信息。在调用 `pthread_attr_init()` 函数后,`attr` 指向的线程属性对象将被初始化为默认状态,
即使用默认属性值。如果需要更改线程的属性,则可以使用其他线程属性相关的函数(如 
`pthread_attr_setschedpolicy()`、`pthread_attr_setstacksize()` 等)来修改属性值。函数返回值为 0 表示初始化成功,否则返回相应的错误代码。

pthread_attr_setschedpolicy
  是一个 Linux 线程 API 函数,用于设置线程属性对象(pthread_attr_t)中的调度策略(scheduling policy)。调度策略是指在多个线程竞争 CPU 资源时,操作系统按照一定的规则来分配 CPU 时间片的方式。

#include <pthread.h>
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);`attr` 参数是指向线程属性对象的指针,而 `policy` 参数则为想要设置的调度策略
。常见的调度策略有以下几种:SCHED_FIFOSCHED_RRSCHED_OTHER在调用 `pthread_attr_setschedpolicy()` 函数之后,线程所使用的调度策略就被设置为 policy
指定的值。需要注意的是,调度策略只能被设置一次,一旦设置就不能更改。如果需要修改调度策略,
则必须先销毁线程属性对象并重新创建一个新的属性对象。函数返回值为 0 表示设置成功,否则返回相应的错误代码。

pthread_attr_setstacksize
  其是一个 POSIX 线程库的函数,用于设置线程的堆栈大小。

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
该函数接受两个参数:
- `attr` 是一个指向线程属性对象的指针。使用 `pthread_attr_init` 初始化线程属性对象,并在调用 `pthread_create` 创建线程时传递给它。- `stacksize` 是一个 `size_t` 类型的值,表示期望的线程堆栈大小,以字节为单位。该函数返回 0 表示成功,非零值表示失败。请注意,线程堆栈大小的最小值可能会受到系统和库的限制。在使用时,应该小心选择堆栈大小以
确保适应线程所需的工作负载。

pthread_attr_setaffinity_np
  其是一个 POSIX 线程库函数,在 Linux 平台上设置线程的 CPU 亲和性(CPU affinity)。CPU 亲和性指定了线程允许在哪些 CPU 核心上执行。

int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);该函数接受三个参数:
- `attr` 是一个指向线程属性对象(`pthread_attr_t`)的指针。使用 `pthread_attr_init` 进行初始化,并在调用 `pthread_create` 时传递给它。- `cpusetsize` 是一个 `size_t` 类型的值,表示 `cpuset` 参数的大小,以字节为单位。一般可以使用 `sizeof(cpu_set_t)` 获取正确的大小。- `cpuset` 是一个 `cpu_set_t` 类型的指针,表示线程允许执行的 CPU 核心集合。可以使用`CPU_ZERO`、`CPU_SET`、`CPU_CLR` 等宏进行设置。该函数返回 0 表示成功,非零值表示失败。

2、示例代码

  提供一个使用 Linux API 实现线程调度策略、设置线程属性、绑定核心的 C 语言代码示例。下面是一个简单的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>// 线程函数1
void* thread_func1(void* arg) {printf("线程1正在运行\n");// 线程1的具体任务逻辑return NULL;
}// 线程函数2
void* thread_func2(void* arg) {printf("线程2正在运行\n");// 线程2的具体任务逻辑return NULL;
}int main() {pthread_t thread1, thread2;pthread_attr_t attr1, attr2;// 初始化线程属性pthread_attr_init(&attr1);pthread_attr_init(&attr2);// 设置线程调度策略:SCHED_FIFO为实时线程,SCHED_OTHER为普通线程pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);pthread_attr_setschedpolicy(&attr2, SCHED_OTHER);// 设置线程栈大小size_t stack_size = 1024 * 1024; // 1MBpthread_attr_setstacksize(&attr1, stack_size);pthread_attr_setstacksize(&attr2, stack_size);// 设置线程名称pthread_attr_setname(&attr1, "Real-Time Thread");pthread_attr_setname(&attr2, "Normal Thread");// 创建线程1,绑定到核心0cpu_set_t cpuset1;CPU_ZERO(&cpuset1);CPU_SET(0, &cpuset1);pthread_attr_setaffinity_np(&attr1, sizeof(cpu_set_t), &cpuset1);pthread_create(&thread1, &attr1, thread_func1, NULL);// 创建线程2,绑定到核心1cpu_set_t cpuset2;CPU_ZERO(&cpuset2);CPU_SET(1, &cpuset2);pthread_attr_setaffinity_np(&attr2, sizeof(cpu_set_t), &cpuset2);pthread_create(&thread2, &attr2, thread_func2, NULL);// 等待线程1和线程2运行结束pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 销毁线程属性pthread_attr_destroy(&attr1);pthread_attr_destroy(&attr2);return 0;
}

  上述代码中,thread_func1()thread_func2() 是分别作为线程1和线程2的函数。通过 pthread_t 数据类型创建线程,并使用 pthread_attr_t 数据类型来设置线程属性。

  在主函数中,我们初始化了线程属性 attr1attr2,并分别为它们设置了调度策略、栈大小、线程名称和绑定的核心。通过调用 pthread_create() 函数创建线程并将线程函数和属性传递给它。

  最后,通过调用 pthread_join() 函数来等待线程1和线程2运行结束,并在程序的末尾销毁线程属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/172580.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统---僵尸进程、孤儿进程

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 键盘敲烂&#xff0c;年薪百万&#xff01; 有了上一篇博客的学习&#xff0c;我们已经简单了解了进程的基础知识&#xff0c;今天我们再来学习两个特殊的进程&#xff0c;僵尸进程和孤儿进程。 …

7000字详解 动态代理(JDK动态代理 CGLIB动态代理)与静态代理

代理模式 1. 代理模式 概念2. 静态代理3. 动态代理3.1.JDK动态代理3.2.CGLIB动态代理3.3. JDK动态代理和CGLIB动态代理区别 4.静态代理和动态代理区别5.篇末 1. 代理模式 概念 代理模式是一种设计模式。 使用代理对象来替代真实对象&#xff0c;用代理对象去访问目标对象。这样…

虚拟化逻辑架构: LBR 网桥基础管理

目录 一、理论 1.Linux Bridge 二、实验 1.LBR 网桥管理 三、问题 1.Linux虚拟交换机如何增删 一、理论 1.Linux Bridge Linux Bridge&#xff08;网桥&#xff09;是用纯软件实现的虚拟交换机&#xff0c;有着和物理交换机相同的功能&#xff0c;例如二层交换&#…

图论 2023.11.27

Kruskal定义不同的优先级 P3623 [APIO2008] 免费道路 给定一个无向图&#xff0c;其中一些边是0&#xff0c;其他边为1 两个不同的点之间都应该一条且仅由一条边连接 并保持刚好K条0&#xff0c;求是否有解决方案 n<2e4,m<1e5 Kruskal定义不同的优先级 思路&#xff1a;…

【NGINX--6】安全控制--1

1、基于 IP 地址的访问 根据客户端的 IP 地址控制访问。 使用 HTTP 或 stream 访问模块控制对受保护资源的访问&#xff1a; location /admin/ { deny 10.0.0.1; allow 10.0.0.0/20;allow 2001:0db8::/32; deny all; }给定的 location 代码块允许来自 10.0.0.0/20 中的任何 …

centos 查看磁盘分区的文件系统类型

1 lsblk -f 这个命令是查看系统可以识别出的所有分区的文件系统类型 # lsblk -f NAME FSTYPE LABEL UUID MOUNTPOINT vda └─vda1 ext4 8c02a225-e14c-44a9-a9d8-4b60c4b…

百面深度学习-自然语言处理

自然语言处理 神经机器翻译模型经历了哪些主要的结构变化&#xff1f;分别解决了哪些问题&#xff1f; 神经机器翻译&#xff08;Neural Machine Translation, NMT&#xff09;是一种使用深度学习技术来实现自动翻译的方法。自从提出以来&#xff0c;NMT模型经历了几个重要的…

#Js篇:Promise

定义 Promise是异步操作解决方案&#xff0c;为异步操作提供统一接口。 Promise英文意思是“承诺”&#xff0c;表示其他手段无法改变。 返回 所有异步任务都返回一个Promise实例。 Promise实例有一个then方法&#xff0c;用于指定下一步的回调函数。 状态 异步操作未完…

一个简易的URL爬虫程序(java)

该程序是一个简单的Java程序&#xff0c;用于从指定的URL中获取网页内容并保存到本地文件。通过URL类打开指定的URL链接&#xff0c;并使用openStream()方法获取输入流。然后使用Scanner类读取输入流中的内容&#xff0c;并使用PrintWriter类将读取到的内容写入到本地文件中。 …

HTTP协议发展

HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) 每一代HTTP解决了什么问题&#xff1f; 下图说明了主要功能。 HTTP 1.0 于 1996 年最终确定并完整记录。对同一服务器的每个请求都需要单独的 TCP 连接。 HTTP 1.1 于 1997 年发布。TCP 连接可以保持打开状态…

php使用Session实现简单购物车功能

一个简单的商城购物车功能。它使用了PHP的会话(Session)来存储购物车数据&#xff0c;通过调用不同的函数来实现添加商品、移除商品、更新商品数量以及清空购物车的功能 session_start();// 初始化购物车 if (!isset($_SESSION[cart])) {$_SESSION[cart] array(); }// 添加商品…

openGauss学习笔记-132 openGauss 数据库运维-查看openGauss状态

文章目录 openGauss学习笔记-132 openGauss 数据库运维-查看openGauss状态132.1 背景信息132.2 前提条件132.3 操作步骤132.4 参数说明132.5 示例 openGauss学习笔记-132 openGauss 数据库运维-查看openGauss状态 132.1 背景信息 openGauss支持查看整个openGauss的状态&#…

如何在Linux系统安装Nginx并启动

Nginx的介绍 Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务器中表现较好。官网&#xff1a;nginx newsNginx的下载 前往…

docker基础学习笔记

文章目录 Docker简介Linux下安装DockerDocker常用命令Docker网络Docker存储docker-composedockerfile制作镜像私有仓库镜像导入导出参考 Docker简介 定义&#xff1a;Docker是一个开源的应用容器引擎优势&#xff1a; 一键部署&#xff0c;开箱即用&#xff1a;容器使用基于im…

Qt5.15.2静态编译 VS2017 with static OpenSSL

几年前编译过一次Qt静态库:VS2015编译Qt5.7.0生成支持XP的静态库,再次编译,毫无压力。 一.环境 系统:Windows 10 专业版 64位 编译器:visual studio 2017 第三方工具:perl,ruby和python python用最新的3.x.x版本也是可以的 这三个工具都需要添加到环境变量,安装时勾选…

057-第三代软件开发-文件监视器

第三代软件开发-文件监视器 文章目录 第三代软件开发-文件监视器项目介绍文件监视器实现原理关于 QFileSystemWatcher实现代码 关键字&#xff1a; Qt、 Qml、 关键字3、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&…

在使用微信或者支付宝支付的时候,为什么微信支付或者支付宝支付的异步通知商户支付结果要进行验签?

在使用微信支付或支付宝支付等第三方支付平台时&#xff0c;异步通知是一种常见的机制&#xff0c;用于通知商户支付结果或交易状态的变化。验签&#xff08;Signature Verification&#xff09;是为了确保异步通知的安全性和完整性而进行的重要步骤。以下是为什么要进行验签的…

人工智能时代的内容写作

内容不再只是王道&#xff0c;正如俗话所说&#xff1a;它是一种流动的货币&#xff0c;推动了巨大的在线信息和影响力经济。 每个品牌都是一个故事&#xff0c;通过其服务和商品讲述自己。尽管如此&#xff0c;大多数客户还是会通过您的在线内容最了解您。 但随着我们进入人…

每日一题:LeetCode-LCR 143.子结构判断

每日一题系列&#xff08;day 05&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

汇编:关于栈的知识

1.入栈和出栈指令 2. SS与SP 3. 入栈与出栈 3.1 执行push ax ↑↑ 3.2 执行pop ax ↓↓ 3.3 栈顶超界的问题 4. 寄存器赋值 基于8086CPU编程时&#xff0c;可以将一段内存当作栈来使用。一个栈段最大可以设为64KB&#xff08;0-FFFFH&#xff09;。 1.入栈和出栈指令…