操作系统进程学习(Linux 内核学习笔记)

操作系统进程学习(Linux 内核学习笔记)

进程优先级

并非所有进程都具有相同的重要性。除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求。首先进程比较粗糙的划分,进程可以分为实时进程非实时进程(普通进程)

实时进程优先级(0-99)都比普通 进程的优先级(100-139)高。当系统中有实时进程运行时,普通进程几乎无法分到时间片(只能分到5%的CPU时间)。

通过时间片运行进程

进程系统调用

​ 讨论fork和exec系列系统调用的实现。通常这些调用不是由应用程序直接发出的,而是通过一个中间层调用,即负责与内核通信的C标准库。从用户状态切换到核心态的方法,依不同的体系结构而各有不同

用户发起一个新进程之后,CPU为进程分配资源,并将硬盘数据读到内存中去,但是用户进程是一个应用级程序,无法直接与CPU进行交互,所以通过系统调用(system_call),加载完成内核就会退出CPU,用户进程执行完毕后,内核进入CPU将用户进程移除,下一个同上image-20210903163111488

  1. 进程复制

    (1) fork是重量级调用,因为它建立了父进程的一个完整副本,然后作为子进程执行。 为减少与该调用相关的工作量,Linux使用了写时复制(copy-on-write)1技术。

    (2) vfork类似于fork,但并不创建父进程数据的副本。相反,父子进程之间共享数据。 这节省了大量CPU时间(如果一个进程操纵共享数据,则另一个会自动注意到)。

    (3) clone产生线程,可以对父子进程之间的共享、复制进行精确控制。

调度器分析

  1. 调度器及其功能

    内核中用来安排进程执行的模块称为调度器(scheduler),它可以切换进程状态 (process state)。例如执行、可中断睡眠、不可中断睡眠、退出、暂停等。 调度器是CPU中央处理器的管理员,主要负责完成做两件事情:一、选择某些就绪进 程来执行,二是打断某些执行的进程让它们变为就绪状态。调度器分配CPU时间的基本依据就 是进程的优先级。上下文 切换(context switch):将进程在CPU中切换执行的过程,内核承担 此任务,负责重建和存储被切换掉之前的CPU状态

主要有两个函数可以获得线程设置的最高和最低优先级:

int sched_get_priority_max(int); // 获取实时优先级最大值
int sched_get_priority_min(int); // 获取实时优先级最小值

设置与获取优先级各个主要函数:

int pthread_attr_setschedparam(pthread_attr_t*,const struct sched_param);//创建线程优先级
int pthread_attr_getschedparam(pthread_attr_t*,const struct sched_param);//获取线程优先级

实战:

#include <assert.h>
#include <iostream>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>static int get_thread_policy(pthread_attr_t *attr) //获取线程调度策略
{int plicy;int rs = pthread_attr_getschedpolicy(attr, &plicy);assert(rs == 0);switch (plicy){case SCHED_FIFO:printf("policy = FIFO");break;case SCHED_RR:printf("policy = RR");break;case SCHED_OTHER:printf("policy=OTHER");break;default:printf("policy = unknown");break;}return plicy;
}static void show_thread_priority(pthread_attr_t *attr, int policy)
{int priority = sched_get_priority_max(policy);assert(priority != -1);printf("max_priority=%d\n", priority);priority = sched_get_priority_min(policy);assert(priority != -1);printf("min_priority=%d\n", priority);
}static int get_thread_priority(pthread_attr_t *attr) //获取线程优先级
{sched_param param;int rs = pthread_attr_getschedparam(attr, &param);assert(rs == 0);printf("priority = %d", param.sched_priority);return param.sched_priority;
}
static void set_thread_policy(pthread_attr_t *attr, int policy)
{int rs = pthread_attr_setschedpolicy(attr, policy);assert(rs == 0);get_thread_policy(attr);
}int main(int argc, char const *argv[])
{pthread_attr_t attr;struct sched_param sched;int rs = pthread_attr_init(&attr);assert(rs == 0);int plicy = get_thread_policy(&attr);printf("输出进程优先级\n");show_thread_priority(&attr, plicy);printf("输出FIFO优先级");show_thread_priority(&attr, SCHED_FIFO);printf("输出RR优先级\n");show_thread_priority(&attr, SCHED_RR);printf("输出当前线程优先级");int priority = get_thread_priority(&attr);printf("设置线程策略\n");printf("设置FIFO策略");set_thread_policy(&attr, SCHED_FIFO);printf("设置RR策略");set_thread_policy(&attr, SCHED_RR);printf("还原线程属性\n");set_thread_policy(&attr, plicy);rs = pthread_attr_destroy(&attr);assert(rs == 0);return 0;
}

实战2

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void threadfunc1()
{sleep(1);int policy;struct sched_param praram;pthread_getschedparam(pthread_self(), &policy, &praram);if (policy == SCHED_OTHER)printf("SCHED_OTHER.\n");if (policy == SCHED_RR);printf("SCHED_RR 1.\n");if (policy == SCHED_FIFO)printf("SCHED_FIFO.\n");for (int i = 1; i <= 10; i++){for (int j = 1; j < 4000000; j++){}printf("Threadfunc1.\n");}printf("pthreadfunc1 EXIT.\n");
}void threadfunc2()
{sleep(1);int policy;struct sched_param praram;pthread_getschedparam(pthread_self(), &policy, &praram);if (policy == SCHED_OTHER)printf("SCHED_OTHER.\n");if (policy == SCHED_RR);printf("SCHED_RR 1.\n");if (policy == SCHED_FIFO)printf("SCHED_FIFO.\n");for (int i = 1; i <= 10; i++){for (int j = 1; j < 4000000; j++){}printf("Threadfunc2.\n");}printf("pthreadfunc2 EXIT.\n");
}void threadfunc3()
{sleep(1);int policy;struct sched_param praram;pthread_getschedparam(pthread_self(), &policy, &praram);if (policy == SCHED_OTHER)printf("SCHED_OTHER.\n");if (policy == SCHED_RR);printf("SCHED_RR 1.\n");if (policy == SCHED_FIFO)printf("SCHED_FIFO.\n");for (int i = 1; i <= 10; i++){for (int j = 1; j < 4000000; j++){}printf("Threadfunc3.\n");}printf("pthreadfunc3 EXIT.\n");
}int main()
{int i;i = getuid();if (i == 0)printf("the current user is root.\n");elseprintf("the current user is not root.\n");pthread_t ppid1, ppid2, ppid3;struct sched_param param;pthread_attr_t attr1, attr2, attr3;pthread_attr_init(&attr2);pthread_attr_init(&attr1);pthread_attr_init(&attr3);param.sched_priority = 51;pthread_attr_setschedpolicy(&attr3, SCHED_RR);pthread_attr_setschedparam(&attr3, &param);pthread_attr_setinheritsched(&attr3, PTHREAD_EXPLICIT_SCHED);param.sched_priority = 22;pthread_attr_setschedpolicy(&attr2, SCHED_RR);pthread_attr_setschedparam(&attr2, &param);pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);pthread_create(&ppid3, &attr1, (void *)threadfunc3, NULL);pthread_create(&ppid2, &attr2, (void *)threadfunc2, NULL);pthread_create(&ppid1, &attr3, (void *)threadfunc1, NULL);pthread_join(ppid3, NULL);pthread_join(ppid2, NULL);pthread_join(ppid1, NULL);pthread_attr_destroy(&attr3);pthread_attr_destroy(&attr2);pthread_attr_destroy(&attr1);return 0;
}

RCU机制

​ RCU英文全称为Read-Copy-Update,顾名思义就是 “读 - 拷贝-更新”,是内核中重要 的同步机制。Linux内核已有原子操作、读写信号量等等锁机制,为何会单独设计一个比较复杂的新机制?

RCU原理

​ RCU记录所有指向共享数据的指针的使用者,当要修改该共享数据时,首先创建一个 副本,在副本中修改。所有读访问线程都离开读临界区之后 ,指针指向新的修改后副本的指针,并且删除旧数据

  1. 写者修改对象的过程:首先生成一个副本,让后更新副本,最后使用新的对象替换旧的对象,在写者执行复制更新的时候读者可以读数据
  2. 写者删除对象:必须等到所有访问的读者访问结束,才能执行销毁操作,RCU技术的关键:如何判断所有的读者已经结束访问,等待所有读者访问时间结束的时间称为宽限期
  3. RCU读者并不需要与写进行同步,读者和写者能够并发执行,RCU目标最大程序来减少读者的开销,因为也经常使用于读者性能要求高的场合

RCU优点:读者开销少,不需要锁,原子指令,内存屏障等,无死锁问题,无内存泄露风险

RCU缺点:写者同步开销比较大,写着之间需要互斥处理,同步机制复杂

image-20210905142136565

内核内存布局

​ ARM64架构处理器采用48位物理寻址机制,最大可寻找256TB的物理地址空间。对于 目前应用完全足够,不需要扩展到64位的物理寻址。虚拟地址也同样最大支持48位寻址,所以 在处理器架构设计上,把虚拟地址空间划分为两个空间,每个空间最大支持256TB,linux内核 在大多数体系结构上都把两个地址划分为:用户空间和内核空间。

用户空间:0x0000_0000_0000_0000至0x0000_ffff_ffff_ffff。

内核空间:0xffff_0000_0000_0000至0xffff_ffff_ffff_ffff

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

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

相关文章

【Linux内核】虚拟地址空间布局架构

虚拟地址空间布局架构(Linux内核学习) 1.Linux内核整体架构及子系统 内核对下管理硬件,对上通过运行时库对应用提供服务 用户空间 使用malloc()分配内存通过free()释放内存 内核空间 虚拟进程负责从进程的虚拟地址空间分配虚拟页,sys_brk来扩大或收缩堆,sys_mmap负责在内存映…

【Linux内核】内存映射原理

【Linux内核】内存映射原理 物理地址空间 物理地址是处理器在总线上能看到的地址,使用RISC(Reduced Instruction Set Computing精简指令集)的处理器通常只实现一个物理地址空间,外围设备和物理内存使用统一的物理空间, 有些架构的处理器把分配给外围设备的物理地址称为设备内存…

javascript学习系列(1):数组中的map方法

最好的种树是十年前,其次是现在。歌谣 每天一个前端小知识 提醒你改好好学习了 知乎博主 csdn博主 b站博主 放弃很容易但是坚持一定很酷 我是歌谣 喜欢就一键三连咯 你得点赞是对歌谣最大的鼓励 1前言 在我们的日常开发中 不免会有很多需要处理数据的方法 本节主要说一说m…

【Linux内核】物理内存组织结构

【Linux内核】物理内存组织结构 系统调用mmap 物理内存组织结构 体系结构 目前多处理器系统有两种体系结构&#xff1a; 1&#xff09;非一致内存访问&#xff08;Non-Unit Memory Access&#xff0c;NUMA&#xff09;&#xff1a;指内存被划分成多个 内存节点的多处理器系…

脱离 Rails 看 Ruby

在开始这篇文章之前&#xff0c;我需要澄清一些事情。首先&#xff0c;这不是一篇关于 Ruby on Rails 的文章。如果您希望了解 Rails&#xff0c;每周&#xff08;甚至每小时&#xff09;都有相关的文章和 blog 出现&#xff0c;它们都对这个令人兴奋的框架的众多特性大加推崇&…

如何方便的让你的集合引发改变事件

在我们开发自定义控件的过程中,我们常常会给控件添加集合属性。比如定制Grid控件就会有Column集合。当集合属性发生变化时&#xff0c;比如添加新元素&#xff0c;删除新元素&#xff0c;我们要通知控件去重绘以反映新的变化。我们可以创建一个集合类&#xff0c;在类里添加一个…

[汇编语言]-第八章 div指令,伪指令dd,dup

1- div除法指令 (1) 除数: 有8位和16位两种,在一个寄存器或内存单元中. (2) 被除数: 默认放在AX和DX或AX中 除数为8位, 被除数为16位, 默认在AX中存放. 除数为16位, 被除数为32位, 在DX或AX中存放. AX存放低16位,DX存放高16位. (3) 结果 除数为8位, 则AL存储除法操作的商, AH存…

lambda表达式浅析【C++学习笔记】

lambda表达式浅析【C学习笔记】 基本用法: auto f [/*捕获列表*/](/*参数*/)->int /*后置返回值类型*/{/** 函数体*/};捕获列表: [] : 不捕获任何变量 [变量名] : 表示值捕获,不可修改 [] :按值捕获所有变量,不可修改 [&] : 按引用捕获可以修改 [this] : 在类中捕…

【Cocos2d-x for WP8 学习整理】(2)Cocos2d-Html5 游戏 《Fruit Attack》 WP8移植版 开源...

【Cocos2d-x for WP8 学习整理】&#xff08;2&#xff09;Cocos2d-Html5 游戏 《Fruit Attack》 WP8移植版 开源 原文:【Cocos2d-x for WP8 学习整理】&#xff08;2&#xff09;Cocos2d-Html5 游戏 《Fruit Attack》 WP8移植版 开源这一阵花了些时间&#xff0c;把 cocos2d-h…

碰撞,处理碰撞,发射 Learn Unreal Engine (with C++)

本文使用打砖块游戏举例 碰撞,处理碰撞 碰撞就相当于一个Actor进入另一个Box中,用这个思路就可以处理碰撞了 OnComponentBeginOverlap 当某些内容开始重叠此组件时调用的事件&#xff0c;例如玩家进入触发器。 **委托 事件 **1 AddDynamic( UserObject, FuncName ) 用于…

传送,条件加速 Learn Unreal Engine (with C++)

本文以吃豆人游戏为例UE4项目: 自制UE4 小游戏 (gitee.com) 传送 pawn进入box触发OnActorBeginOverlap获取目标位置,下一帧将pawn坐标更改为目标位置 首先需要重叠函数与开始重叠事件绑定 OnActorBeginOverlap.AddDynamic(this, &ATeleporterActor::OnOverlapBegin);头文件…

获取摄像机,摄像机切换Learn Unreal Engine (with C++)

摄像机应该是使用最普遍的组件了 获取摄像机,摄像机切换 新建C类(以CameraActor为父类) 将摄像机在地图中放置 头文件声明 virtual void BeginPlay() override;UPROPERTY(EditAnywhere, BlueprintReadWrite)UBoxComponent* OverlapVolume; // 盒体组件,用于检测人物碰撞UPR…

android报错及解决1--Bitmap加载时,报bitmap size exceeds VM budget

报错描述&#xff1a; 用Bitmap加载图片资源时&#xff0c;报错java.lang.OutOfMemoryError: bitmap size exceeds VM budget 原因分析&#xff1a; android系统限制&#xff0c;只给图片分配8M内存&#xff0c;超过就蹦。图片虽然几十K&#xff0c;可能是压缩格式&#xff0c;…

主角的创建与选择 Learn Unreal Engine (with C++)

主角创建有两种方式,本教程以SpaceshipBattle fanxingin/UE4项目 - 码云 - 开源中国 (gitee.com) 1. 新建游戏模式方式 新建一个蓝图类,选择游戏模式基础 在蓝图类的细节中将默认pawn类选择主角的蓝图类 在项目设置->地图和模式->默认模式->默认游戏模式 默认游…

控制`Actor`朝向,运动 Learn Unreal Engine (with C++)

控制Actor的朝向,以及Actor的运动 SpaceshipBattle fanxingin/UE4项目 - 码云 - 开源中国 (gitee.com) 控制Actor朝向鼠标 设置鼠标在游戏中可见 获取玩家控制器鼠标可见设置为true PC Cast<APlayerController>(GetController()); PC->bShowMouseCursor true;获取…

.Net开发人员应该下载的十种必备工具(三)

NDoc 编写代码文档资料几乎总是一项令人畏惧的任务。我所说的不是早期设计文档&#xff0c;甚至也不是更为详细的设计文档&#xff1b;我说的是记录类上的各个方法和属性。NDoc 工具能够使用反射来分析程序集&#xff0c;并使用从 C# XML 注释生成的 XML 自动为代码生成文档资料…