Linux多线程编程中的调度策略编程

news/2024/11/16 10:27:14/

多线程编程

我们在进行多线程编程的时间,通常先会对问题领域进行任务的拆解,深入一点的多线程编程,会涉及到任务优先级的考虑;如果再深一点,一般可能就是多核编程:Cache热度、绑核、隔离CPU等。

但多核编程与具体硬件绑定较为紧密,通用性比较差,不到万不得已的时候,多核编程实为下策,应避免用之!

在此,要介绍的是在多线程编程中调度策略编程。相较于多核编程,可能更贴合普通的使用场景!

由来

对于某一些任务类型,例如,负载均衡器LB,这类任务有相当的密集CPU使用需求,但又不是100%的CPU消耗。在普通Linux CFS公平调度策略下,任务在时间片到时需要被换下马重新调度,在需要执行时,又因为历史上CPU使用时间的“被动”,经过动态计算优先级,又不一定能够马上被调度起来,可能会造成某些程度的丢包!

但在Linux系统分为实时系统和非实时系统,以前因为认知上的偏差,对于Linux CFS公平调度策略小小有点不满,为什么不可以实现线程调度策略定制的自由呢?

确实,Linux是自由的!近来,通过查看man 7 sched,让自己满足地惊艳了一把,原来Linux早就实现了这种定制需求!

多核编程不见得效果更好,建议使用通用性更好的实时调度策略编程 😃

SCHED_RR实时调度策略

在Linux中调度策略分为实时调度策略和非实时策略。

深入分析了下SCHED_RR策略,此种调度策略已经可以比较好地满足实时性要求高和CPU使用密集的负载平衡器的多线程任务场景。

直白一点说就是:对于CPU较为密集使用的场景,想在自己退让CPU使用时,才脱离CPU执行;而当想使用CPU时,又可以获得较为实时的调度,上马执行

SCHED_RR实时调度策略,在调度等级上高于普通调度策略;同时实时任务优先级为静态优先级,不进行动态调整

通过控制内核最长使用CPU时间片时间/proc/sys/kernel/sched_rr_timeslice_ms,可以以控制任务在需要退让CPU使用时,才脱离CPU使用

通过查看/proc/{pid}/statusvoluntary_ctxt_switches、nonvoluntary_ctxt_switches两个统计项,可以观察任务主动让出CPU和被动让出CPU的比值,以量化策略控制的效果

结束语

在适合的多线程场景,建议多线程编程定制合适的调度策略

附录例子

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#define __USE_GNU
#include <sched.h>
#include <signal.h>static int g_exit;
static void term_handler(int s)
{g_exit = 1;
}/** cat /proc/sys/kernel/sched_rt_runtime_us* cat /proc/sys/kernel/sched_rr_timeslice_ms* cat /sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us* echo $((10*1000)) > /sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us
*/
int main(int argc , char* argv[])
{char szErrorDesc[256];struct sigaction act, oldact;act.sa_handler  = term_handler;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGINT, &act, &oldact);sigaction(SIGTERM, &act, &oldact);//signal(SIGINT, SIG_IGN);pid_t pid = getpid();printf("pid: %d, policy: %d\n", pid, sched_getscheduler(pid));int policy = -1;int opt;while((opt = getopt(argc, argv, "rb")) != -1) {switch(opt) {case 'r':policy = SCHED_RR;break;case 'b':policy = SCHED_BATCH;break;default: /* '?' */fprintf(stderr, "Usage: %s [-r --SCHED_RR] [-b --SCHED_BATCH] \n", argv[0]);return 1;}}if(policy != -1) {struct sched_param tParam = {};if(policy == SCHED_RR)tParam.sched_priority = 1;int rc = sched_setscheduler(pid, policy, &tParam);if(rc < 0){strerror_r(errno, szErrorDesc, sizeof(szErrorDesc));fprintf(stderr, "sched_setscheduler fail, errno: %d, %s", errno, szErrorDesc);}else{printf("after set thread policy: %d\n", sched_getscheduler(pid));}   }char szCmd[64];snprintf(szCmd, sizeof(szCmd), "cat /proc/%d/status", pid);printf("can see %s to see the context switch\n", szCmd);uint64_t count = 0;while(g_exit == 0) {++count;}printf("cat %s to see the context switch result\n", szCmd);system(szCmd);return 0;
}

http://www.ppmy.cn/news/977730.html

相关文章

ARM DAY3 点亮三盏灯

1.汇编代码 .text .global _start _start: //RCC初始化 RCC_INIT://设置GPIOE组使能ldr r0,0x50000A28ldr r1,[r0]orr r1,r1,#(0x1<<4)str r1,[r0]//设置GPIOF组使能 ldr r0,0x50000A28ldr r1,[r0]orr r1,r1,#(0x1<<5)str r1,[r0]//LED1灯初始化 LED1_INIT://设置…

【档案专题】四、电子档案形成与收集

导读&#xff1a;主要针对电子档案形成与收集相关内容介绍。对从事电子档案管理信息化的职业而言&#xff0c;不断夯实电子档案管理相关理论基础是十分重要。只有通过不断梳理相关知识体系和在实际工作当中应用实践&#xff0c;才能走出一条专业化加职业化的道路&#xff0c;从…

【Nodejs】Node.js开发环境安装

1.版本介绍 在命令窗口中输入 node -v 可以查看版本 0.x 完全不技术 ES64.x 部分支持 ES6 特性5.x 部分支持ES6特性&#xff08;比4.x多些&#xff09;&#xff0c;属于过渡产品&#xff0c;现在来说应该没有什么理由去用这个了6.x 支持98%的 ES6 特性8.x 支持 ES6 特性 2.No…

STM32(HAL库)驱动AD8232心率传感器

目录 1、简介 2、CubeMX初始化配置 2.1 基础配置 2.1.1 SYS配置 2.1.2 RCC配置 2.2 ADC外设配置 2.3 串口外设配置 2.4 GPIO配置 2.5 项目生成 3、KEIL端程序整合 3.1 串口重映射 3.2 ADC数据采集 3.3 主函数代码整合 4 硬件连接 5 效果展示 1、简介 本文通过STM32…

Qt - 信号和槽

文章目录 信号和槽自定义信号和槽代码实现teacher 类申明信号方法student 添加槽并处理绑定信号和槽 当自定义信号和槽出现重载设置按钮点击 信号可以连接信号断开信号 disconnectQt4版本写法Lambda 表达式函数对象参数操作符重载函数参数可修改标示符函数返回值是函数体 总结拓…

运维高级学习---MySQL主从复制

MySQL内建的复制功能是构建大型&#xff0c;高性能应用程序的基础 通过将MySQL的某一台主机 (master)的数据复制到其他主机(slaves)上&#xff0c;并重新执行一遍来执行复制过程中一台服务器充当主服务器&#xff0c;而其他一个或多个其他服务器充当从服务器 为什么要做主从复…

appscan 应用

HCL appscan是个常见的web app DAST 扫描工具 有企业版和standalone 版本。大家常用的都是单机版本。企业版平台&#xff0c;集成了IAST。 appscan 使用比较简单&#xff0c;基本输入url 账号密码就开扫了。 用了一段时间几点体验 1 还是需要手动explore的&#xff0c;他自…

Python3 API 的封装及调用

一、API 的封装 API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作…