linux之进程

一、背景

冯.诺依曼体系结构

输入设备键盘、鼠标、摄像头、话筒、磁盘、网卡...
输出设备显示器、声卡、磁盘、网卡...
CPU运算器、控制器
存储器一般就是内存

        数据在计算机的体系结构进行流动,流动过程中,进行数据的加工处理,从一个设备到另一个设备,本质:这是一种拷贝!

        数据设备间拷贝的效率,决定了计算机整机的基本效率。

在硬件数据流动角度,在数据层面

1.CPU不和外设打交道,CPU和内存打交道。

2.外设(输入和输出)的数据,要先放到内存中

eg。程序运行,为什么要加载到内存?

二、操作系统

1.OS概念:

        操作系统是一个软硬件资源管理的软件。

广义上的认识:操作系统的内核 + 操作系统的外壳周边程序

狭义上的认识:只考虑操作系统的内核

2.结构示意图(简单示意图)

层状划分

3.尝试理解操作系统 --- "管理"

 不需要管理者和被管理者直接接触

 拿到数据才是目的,本质是对数据进行管理

任何管理

先描述,在组织

一个完整的操作系统包含对相关内容的管理和系统调用接口

为什么需要操作系统?

操作系统对下(手段)进行软硬件管理工作,对上层提供良好(高效、稳定、安全)的运行环境(目的)

三、进程

1.进程的理解

进程=内核task_struct结构体 + 程序代码和数据 (形象理解)

PCB(process control block):进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。

        linux下具体称呼为 struct task_struct { //linux进程控制块}

如何理解进程动态运行?

        只要我们的进程task_struct将来在不同的队列中,进程就可以访问不同的资源。

2.进程task_struct本身内部的属性有哪些

1.启动

        1>  ./XXXX ,本质时让系统创建进程并且运行 -- 我们自己写的代码形成的可执行 == 系统命令 == 可执行文件。在linux中运行的大部分执行操作,本质上都是运行进程!

        ps axj | head -1 && ps axj | grep 进程 :可用于查看当前进程状态并且加上标头

        2> 每一个进程 都有自己的唯一标识符,叫做进程pid (unsignen int pid)

        3> 一个进程想知道自己的pid? getpid函数

        4> ctrl+c在用户层面上终止程序,kill -9 pid,可以直接杀掉进程标识符为pid的进程

        2.进程创建的代码方式

1.pid 和 ppid(父进程与子进程)

                pid_t getppid(void) --- 获得当前进程父进程的pid

fork函数,fork之后,父子代码共享

        创建一个进程,本质上是系统多一个进程,多一个进程就是多个 1.内核task_struct 2.自己的代码和数据

        提问,父进程的代码和数据是从磁盘加载而来的,那子进程的代码和数据是从何而来的?

                默认是继承父进程的代码和数据

2.而我们为什么要创建子进程?

        答案是我们想让子进程跑跟父进程不一样的代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
  printf("process is running,only me! pid: %d\n", getpid());    
  sleep(3);    
  pid_t id = fork();     
  if(id == -1) return 1;    
  else if(id == 0)    
  {    
    //child    
    while(1)    
    {    
      printf("id = %d, i am child process! pid: %d ppid:%d\n", id, getpid(), getppid());        
      sleep(1);    
    }    
  }    
  else    
  {    
    //parent    
    while(1)    
    {    
      printf("id = %d, i am parent process! pid: %d ppid:%d\n", id,getpid(), getppid());        
      sleep(2);                                                                  
    }    
    
  }
  return 0;    
}

id = 0  =>  子进程执行

id = 子进程pid  => 父进程执行

杀掉父子进程任一进程都不会影响另一个进程的执行。不过另一个进程会跑到后台,这个后面再说

四、进程状态

1.linux的进程状态

struct tesk_struct
{
    //内部的一个属性
    int status;
};
static const char * const task_state_array[] = {
    "R (running)",         /* 0 */
    "S (sleeping)",        /* 1 */
    "D (disk sleep)",      /* 2 */
    "T (stopped)",         /* 4 */
    "t (tracing stop)",    /* 8 */
    "X (dead)",            /* 16 */
    "Z (zombie)",          /* 32 */
};

R运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列 里。

S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。

D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行。

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

2.僵尸进程和孤儿进程

1.僵尸进程

#include <stdio.h>    
#include <sys/types.h>    
#include <unistd.h>    
    
int main()    
{    
  pid_t id = fork();    
  if(id == 0)    
  {    
    int cnt = 5;    
    while(cnt--)    
    {    
      printf("i am child process! cnt: %d pid: %d\n", cnt, getpid());
      sleep(1);    
    }    
  }    
  else    
  {    
    while(1)    
    {    
      printf("i am parent process! pid: %d\n", getpid());                
      sleep(1);    
    }    
  }    
  return 0;    
}  

运行示意图

Z --- 表示僵尸状态

在子进程执行完后,就变成了一个

僵尸进程:已经运行完毕,但是需要维持自己的退出信息,在自己的进程task_struct 会记录自己的退出信息,未来让父进程来进行读取。

        如果没有父进程读取,僵尸进程会一直存在!会引起内存泄漏问题

2.孤儿进程

修改一下代码,把cnt挪到父进程去,则

父进程如果先退出,子进程就会变成孤儿进程。孤儿进程一般都是会被1号进程(可看作OS本身)进行领养的。

孤儿进程为什么要被OS领养?因为依旧要保证子进程正常被回收。

我们直接在命令行启动的进程,它的父进程是bash,bash会自动回收新进程的Z

3.进程的阻塞、挂起和运行

让多个进程以切换的方式进行调度,在一个时间段内同时得以推进代码,就叫做并发

任何时刻,都同时有多个进程在同时运行,就叫做并行

阻塞态:

挂起态:

进程切换:

CPU内部的所有的寄存器中的临时数据,叫做进程的上下文。

进程在切换,最重要的一件事情就是:上下文数据的保护和恢复

CPU内的寄存器:

        寄存器本身是硬件,具有数据的存储能力,CPU的寄存器硬件只有一套

        CPU内部的数据,可以有多套,有几个进程,就有几套和该进程对应的上下文数据

                寄存器!=寄存器的内容

五、进程优先级

1.什么是优先级

指定进程获取某种资源的先后顺序

task_struct 进程控制块 ->  struct -> 内部字段 -> int prio = ???

linux中优先级数字越小,优先级越高

优先级:已经能,但是看顺序。  权限:能不能?的问题

2.为什么需要优先级

进程需要访问的资源(CPU)始终有限的,系统进程大都挺多的。

操作系统关于调度和优先级的原则:分时操作系统,基本的公平。如果进程因为长时间不被调度,就会造成饥饿问题

3.Linux优先级的特点和查看方式

PRI:进程优先级

NI:进程优先级的修正数据,nice值, 新的优先级 = 优先级 + nice ,达到对于进程优先级动态修改的过程。

注:1.nice值不能随意修改,它是有调整范围的。[-20,19]  40个数字,每次调整优先级,都是从80开始的。

修改方式:top->进入后按‘r’->输入pid->输入nice值

六、命令行参数和环境变量

1.命令行参数

int main(int argc, char* argv[])

这些参数可带可不带。

这些参数的意义:int argc, char* argv[]

先看现象

引出功能

 为什么需要命令行参数?

        本质,命令行参数本质是要交给我们程序不同的选型,用来定制不同的程序功能,命令中会携带很多的选项。

2.环境变量

为什么ls这种函数不需要带地址呢,而我们的process需要带上./?

linux中存在一些全局的设置,表明,告诉命令行解释器,应该去那些路径下寻找可执行程序

 系统中很多配置,在我们登录linux系统的时候,已经被加载到了bash进程中(内存)。

如何添加环境变量?

最开始的环境变量不是在内存中,而是在系统的对应的配置文件中。

查看所有的环境变量: env

自己导入环境变量: export name=value

       取消环境变量: unset name

本地变量

3.整体理解环境变量、系统和我们的程序结合

父进程的数据,默认能被子进程看到并访问。

bash进程启动时,默认会给子进程形成两张表

argv[]命令行参数表,environ[]环境变量表(从OS的配置文件来),bash通过各种方式交给子进程

环境变量具有系统级的全局属性,因为环境变量本身会被子进程继承下去

获取环境变量(代码级)

1.extern char **environ

2.通过main函数参数

3.getenv("PATH")

本地变量只在本bash内部有效,无法被子进程继承下去

导成环境变量。此时才能够被获取

echo export 为内建命令

七、程序地址空间(进程的地址空间)

1.引入

#include <stdio.h>    
#include <sys/types.h>    
#include <unistd.h>    
#include <string.h>    
#include <stdlib.h>    
    
int g_val = 100;    
    
int main()    
{    
  printf("fasther is running, pid = %d, ppid = %d, g_val = %d, &g_val = %p\n", getpid(), getppid(), g_val, &g_val);    
  pid_t id = fork();    
  while(1)    
  {    
    if(id == 0)    
    {    
      int cnt = 0;    
      while(1)    
      {    
        printf("i am a child process, pid = %d, ppid = %d, g_val = %d, &g_val = %p\n", getpid(), getppid(), g_val, &g_val);    
        sleep(1);    
        ++cnt;    
        if(cnt == 5)    
        {    
          g_val = 300;    
          printf("i am child process, g_val change %d -> %d\n",100,300);                                                                             
        }    
      }    
    }    
    else    
    {    
      while(1)    
      {    
        printf("i am a parent process, pid = %d, ppid = %d, g_val = %d, &g_val = %p\n", getpid(), getppid(), g_val, &g_val);    
        sleep(1);    
      }    
    }    
  }    
} 

父子进程具有独立性

注:这个地址绝不是物理地址,是虚拟地址

2.理解

子进程会把父进程的很多内核数据结构全拷贝一份

OS自主完成写时拷贝 --- 按需申请

独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。

通过调整拷贝的时间书匈奴,达到有效节省空间的目的

1.如何理解地址空间?

        1>什么是划分区域?

                地址空间结构体源代码

               地址空间本质是内核的一个struct结构体!内部很多属性都是表示start end的范围

2.为什么要有地址空间?

        1.将无序变成有序,让进程以统一的视角看待物理内存以及自己运行的各个区域!

        2.进程管理模块和内存管理模块进行解耦。

        3.拦截非法请求 -> 对物理内存进行保护     

3.如何进一步理解页表和写时拷贝

        OS识别错误时:1.是不是数据不在物理内存 -> 缺页中断

                                   2.是不是数据需要写时拷贝 -> 发生写时拷贝

                                   3.如果都不是,才会进行异常处理。

4.如何理解虚拟地址

        虚拟地址空间 -> 页表 -> 物理地址

        提问:在最开始的时候,地址空间页表里面的数据从何而来?

                程序里面本身就有地址  --- 虚拟地址(逻辑地址)

int main()    
{    
  pid_t id = fork();    
    if(id == 0)    
    {    
      while(1)    
      {    
        printf("i am a child process id:%d, &id:%p\n",id,&id);    
        sleep(1);    
      }    
    }    
    else if(id > 0)    
    {    
      while(1)    
      {    
        printf("i am a parent process id:%d, &id:%p\n",id,&id);    
        sleep(1);                                                                                                                                    
      }    
    }    
  return 0;    
} 

fork() 之后需要return,return 的本质是对id进行写入,发生写时拷贝,虚拟地址相同,但物理地址不同

八、实例:linux2.6内核进程调度队列

进程调度大O(1)算法

两个array数组结构体,一个结构体只出不进,用actice指向。一个结构体只进不出,用expired指向。bitmap是位图,只需5次便可扫描出queue中是否还有数据。queue则管理各种优先级的进程,[100,139].arrive指向的结构体清空后,则交换active和expired两个指针。从而交替进行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网上兼职赚钱攻略:六种方式让你轻松上手

在互联网时代&#xff0c;网上兼职已经成为一种非常流行的赚钱方式。对于许多想要在家里挣钱的人来说&#xff0c;网上兼职不仅可以提供灵活的工作时间&#xff0c;还可以让他们在自己的兴趣领域中寻求机会&#xff0c;实现自己的财务自由。 在这里&#xff0c;我将为您介绍六…

OpenGL 实现“人像背景虚化“效果

手机上的人像模式,也被人们称作“背景虚化”或 ”双摄虚化“ 模式,也称为 Bokeh 模式,能够在保持画面中指定的人或物体清晰的同时,将其他的背景模糊掉。突出画面的主体部分,主观上美感更强烈。 人像模式的一般实现原理是,利用双摄系统获取景深信息,并通过深度传感器和图…

带流量主功能的外卖菜谱小程序源码:助你轻松领取优惠券,个人使用也可通过审查

外卖菜谱小程序源码-带流量主功能-外卖领劵个人也可过审 这套小程序优点就带很多菜谱&#xff0c;各种你爱吃菜的做法与各类食材介绍营养搭配&#xff0c;相信很多小姐姐会感兴趣。 宝妈宝爸这个小程序肯定能留的住这个群体的人脉流量&#xff0c;这是小程序最大的亮点&#…

深圳区块链交易所app系统开发,撮合交易系统开发

随着区块链技术的迅速发展和数字资产市场的蓬勃发展&#xff0c;区块链交易所成为了数字资产交易的核心场所之一。在这个快速发展的领域中&#xff0c;区块链交易所App系统的开发和撮合交易系统的建设至关重要。本文将探讨区块链交易所App系统开发及撮合交易系统的重要性&#…

【QGIS从shp文件中筛选目标区域导出为shp】

文章目录 1、写在前面2、QGIS将shp文件中目标区域输出为shp2.1、手动点选2.2、高级过滤 3、上述shp完成后&#xff0c;配合python的shp文件&#xff0c;即可凸显研究区域了 1、写在前面 利用shp文件制作研究区域mask&#xff0c;Matlab版本&#xff0c;请点击 Matlab利用shp文…

【Leetcode】单链表常见题

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;Leetcode刷题 本节内容我们来讲解常见的几道单链表的题型&#xff0c;文末会赋上单链表增删查&#xff0c;初始化等代码 目录 1.移除链表元素2.链表的中间节点3.返回倒数第K个节点&#xff1a;4.环…

【Java - 框架 - Lombok】(1) 普通Java项目通过Lombok+Logback完成日志的创建使用 - 快速上手

普通Java项目通过"Lombok""Logback"完成日志的创建使用 - 快速上手&#xff1b; 步骤A 说明 创建"Maven"项目&#xff1b; 图片 步骤B 说明 添加相关依赖项&#xff1b; 图片 代码 <!-- "Lombok"依赖项--> <dependency>&…

C语言--动态内存管理

为什么存在动态内存管理&#xff1f; 在之前我们讲到的类型创建的变量再空间开辟好之后就不能再改变了&#xff0c;但是有时候我们希望能够自由地为某个变量分配空间&#xff0c;就比如上一篇文章中的通讯录&#xff0c;在没有动态内存管理情况下&#xff0c;我们就只能为通讯…

18.字面量

文章目录 一、字面量二、区分技巧三、扩展&#xff1a; /t 制表符 一、字面量 在有些资料&#xff0c;会把字面量说成常量、字面值常量&#xff0c;这种叫法都不是很正确&#xff0c;最正确的叫法还是叫做&#xff1a;字面量。 作用&#xff1a;告诉程序员&#xff0c;数据在…

地物波谱库共享网站汇总

ENVI自5.2版本重新梳理了原有的标准波谱库&#xff0c;新增一些物质波谱&#xff0c;在ENVI5.6中存放在…\Harris\ENVI56\ resource\speclib&#xff0c;分别存放在四个文件夹中&#xff0c;储存为ENVI波谱库格式&#xff0c;有两个文件组成&#xff1a;.sli和.hdr。 ENVI保留…

小米还涉足了哪些领域

小米作为一家全球性的移动互联网企业&#xff0c;其业务领域相当广泛&#xff0c;除了核心的智能手机业务外&#xff0c;还涉足了许多其他领域。以下是对小米涉足领域的简要介绍&#xff1a; 智能硬件与IoT平台&#xff1a;小米是全球领先的智能硬件和IoT平台公司&#xff0c;致…

linux:线程同步

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言线程同步条件变量接口简单示例pthread_cond_wait为什么要有mutex伪唤醒问题的解决 (if->while) 总结 前言 本文作为我对于线程同步知识总结 线程同步 同步&…

资讯头条P3自媒体搭建

自媒体素材管理与文章管理 一.后台搭建 1.1 搭建自媒体网关 导入网关模块>>>在网关模块的pom.xml文件中添加该子模块>>>刷新maven <modules><module>heima-leadnews-app-gateway</module><!--新增--><module>heima-leadnew…

Aurora插件安装

介绍 Latext是一种基于TEX的排版系统。 CTeX中文套装是基于Windows下的MiKTeX系统&#xff0c;集成了编辑器WinEdt和PostScrip处理软件Ghostscript和GSview等主要工具。CTeX中文套装在MikTeX的基础上增加了对中文的完整支持。 CTeX&#xff1a; CTeX套装 - CTEX 下载安装 然后…

【Java程序设计】【C00345】基于Springboot的船舶监造管理系统(有论文)

基于Springboot的船舶监造管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 项目获取 &#x1f345;文末点击卡片获取源码&#x1f345; 开发环境 运行环境&#xff1a;推荐jdk1.8&#xff1b; 开发工具&#xff1a;eclipse以及i…

Day50:WEB攻防-PHP应用文件包含LFIRFI伪协议编码算法无文件利用黑白盒

目录 文件包含-原理&分类&利用&修复 文件读取 文件写入 代码执行 远程利用思路 黑盒利用-VULWEB 白盒利用-CTFSHOW-伪协议玩法 78-php&http协议 79-data&http协议 80-81-日志包含 87-php://filter/write&加密编码 88-data&base64协议 …

韩顺平Java | C21网络编程

1 网络的相关概念 ip地址的组成&#xff1a;网络地址 主机地址 A类&#xff1a;0 ~ 2^7-1 0 ~ 127 B类&#xff1a;128 ~ 1282^6-1 128 ~ 191 C类&#xff1a;192 ~ 1922^5-1 192 ~ 223 D类&#xff1a;224 ~ 2242^4-1 224 ~ 239 E类&#xff1a;240 ~ 2402^3-1 240 ~ 2…

Unity PS5开发 天坑篇 之 URP管线与HDRP管线部署流程以及出包介绍04

目录 一, URP管线、HDRP管线下的Unity项目部署 1. PS5开发论坛关于Unity可支持的版本说明: 2. URP管线下的项目与部署 2.1 Build PS5 URP Project 2.2 运行画面 3. HDRP管线下的项目与部署 3.1 附上可以运行的画面: 4. PS5打包方式介绍 4.1 PC串流调试模式: Build Typ…

selenium自动化测试

selenium自动化测试 1、Javaselenium环境搭建2、测试&#xff0c;打开任意网页3、selenium 常见的Api3.1元素定位findElement3.1.1 css 选择语法3.1.2 xpath 选择语法 1、Javaselenium环境搭建 下载chromedriver&#xff0c;版本要与Chrome浏览器版本一致。 下载之后将chro…

算法打卡day25|回溯法篇05|Leetcode 491.递增子序列、46.全排列、47.全排列 II

算法题 Leetcode 491.递增子序列 题目链接:491.递增子序列 大佬视频讲解&#xff1a;递增子序列视频讲解 个人思路 和昨天的子集2有点像&#xff0c;但昨天的题是通过排序&#xff0c;再加一个标记数组来达到去重的目的。 而本题求自增子序列&#xff0c;是不能对原数组进行…