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两个指针。从而交替进行。

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

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

相关文章

Qt 多线程QThread的四种形式

重点&#xff1a; 1.互斥量&#xff1a;QMutex配套使用&#xff0c;lock(),unlock(),如果一个线程准备读取另一个线程数据时候采用tryLock()去锁定互斥量&#xff0c;保证数据完整性。 QMutexLocker简化版的QMutex,在范围区域内使用。 QMutex mutex QMutexLocker locker(&…

【unity】如何汉化unity编译器

在【unity】如何汉化unity Hub这篇文章中&#xff0c;我们已经完成了unity Hub的汉化&#xff0c;现在让我们对unity Hub安装的编译器也进行下汉化处理。 第一步&#xff1a;在unity Hub软件左侧栏目中点击安装&#xff0c;选择需要汉化的编译器&#xff0c;再点击设置图片按钮…

Dubbo启动流程

Java面试题 Dubbo启动流程 1.服务提供者将服务实例化后注册到注册中心。 2.服务消费者向注册中心订阅所需的服务。 3.注册中心将服务提供者注册的服务地址推送给服务消费者&#xff0c;同时基于长链接推送变更。 4.服务消费者通过代理对象&#xff08;Proxy&#xff09;发起远…

Java毕业设计-基于springboot开发的休闲娱乐代理售票系统-毕业论文+答辩PPT(附源代码+演示视频)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1、开发说明2、需求分析3、系统功能结构 三、系统实现展示1、系统功能模块2、后台登录2.1管理员功能2.2用户功能 四、毕设内容和源代码获取总结 Java毕业设计-基于springboot开发的休闲娱乐…

腾讯云优惠券领取及使用常见问题解答

随着云计算的普及&#xff0c;腾讯云作为国内领先的云计算服务提供商&#xff0c;为越来越多的企业和个人提供了丰富的云产品和服务。为了帮助用户更好地了解和使用腾讯云优惠券&#xff0c;本文将为大家解答关于腾讯云优惠券领取及使用的常见问题。 一、腾讯云优惠券概述 腾讯…

利用互斥锁解决缓存击穿问题

2.9 利用互斥锁解决缓存击穿问题 核心思路&#xff1a;相较于原来从缓存中查询不到数据后直接查询数据库而言&#xff0c;现在的方案是 进行查询之后&#xff0c;如果从缓存没有查询到数据&#xff0c;则进行互斥锁的获取&#xff0c;获取互斥锁后&#xff0c;判断是否获得到了…

包子凑数(蓝桥杯,闫氏DP分析法)

题目描述&#xff1a; 小明几乎每天早晨都会在一家包子铺吃早餐。 他发现这家包子铺有 N 种蒸笼&#xff0c;其中第 i 种蒸笼恰好能放 Ai 个包子。 每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买 X 个包子&#xff0c;卖包子的大叔就会迅速选出若干笼…

爱上数据结构:顺序表和链表

一、线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条…

netty rpc框架 即时通讯

Netty是Java领域有名的开源网络库&#xff0c;特点是高性能和高扩展性&#xff0c;因此很多流行的框架都是基于它来构建的&#xff0c;比如我们熟知的Dubbo、Rocketmq、Hadoop等&#xff0c;针对高性能RPC&#xff0c;一般都是基于Netty来构建&#xff0c;比如sock-bolt。总之一…

2024-3-28 市场情绪强修复

这一轮退潮负反馈都修复了&#xff0c; 艾艾精工 博信股份 安奈尔 永悦科技 大理药业 &#xff0c;高新发展 也补跌了&#xff0c;收尸队也干活了&#xff0c;情绪不修复不接力得最好写照。这轮周期 宁科生物 已经7板&#xff0c;已经追平了 博信股份7板&#xff0c;看明天溢…

18.字面量

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

环信IM集成教程---消息转发合并转发的实现

前言 在发送消息体系中&#xff0c;转发消息是一个重要的环节&#xff0c;可以单条转发也可以合并转发。本文教大家在接入环信IM过程中如何实现单条转发&#xff0c;合并转发消息功能&#xff0c;同时举例一些容易踩坑的位置&#xff0c;以便大家尽快顺利的实现转发消息功能。…

高效 CUDA 调试:将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具

高效 CUDA 调试&#xff1a;将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具 NVIDIA Compute Sanitizer 是一款功能强大的工具&#xff0c;可以节省您的时间和精力&#xff0c;同时提高 CUDA 应用程序的可靠性和性能。 在 CUDA 环境中调试代码既具有挑…

Exception in thread “main“ com.fasterxml.jackson.databind.JsonMappingException:

问题&#xff1a;jaskson反序列化超出最大长度 Caused by: com.fasterxml.jackson.core.exc.StreamConstraintsException: String length (5043456) exceeds the maximum length (5000000) 场景&#xff1a;前端传递过大base64 原因&#xff1a; jaskon默认已经限制了最大长…

20个超实用Python魔法方法

大家好&#xff01;今天我们要一起探索Python世界的神秘角落——那些被称为“魔法方法”的特殊成员方法。它们就像是编程中的魔法咒语&#xff0c;赋予你的类各种神奇特性&#xff0c;让你的代码更加简洁、强大且有趣味&#xff01; __init__&#xff1a;这是每个对象出生时都要…

安卓利用CameraX 拍照获这张照片的exif信息

一、首先导入相关权限 <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /><uses-featureandroid:name"android.hardware.camera"android:required"true" /><uses-permission android:name"andro…

蓝桥杯练习题总结(三)线性dp题(摆花、数字三角形加强版)

目录 一、摆花 思路一&#xff1a; 确定状态&#xff1a; 初始化&#xff1a; 思路二&#xff1a; 确定状态&#xff1a; 初始化&#xff1a; 循环遍历&#xff1a; 状态转移方程&#xff1a; 二、数字三角形加强版 一、摆花 题目描述 小明的花店新开张&#xff0c;为了吸…

Uni-app/Vue/Js本地模糊查询,匹配所有字段includes和some方法结合使用e

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1.第一步 需要一个数组数据 {"week": "全部","hOutName": null,"weekendPrice": null,"channel": "门市价","hOutId": 98,"cTime": "…

【Redis】Redis 内存管理,Redis事务,bigkey和hotkey

目录 Redis 内存管理 缓存数据设置过期时间&#xff1f; Redis 是如何判断数据是否过期的呢&#xff1f; 过期删除策略 内存淘汰机制 主从模式下对过期键的处理&#xff1f; LRU和LFU的区别 Redis事务 定义和原理 Redis 事务的注意点&#xff1f; 为什么不支持回滚&a…

SQLite数据库文件损坏的可能几种情况(一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十三&#xff09; 下一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; 概述 SQLite数据库具有很强的抗损坏能力。如果应用程序崩溃&#xff0c…