linux进程总结

冯诺依曼体系结构

现代计算机中的硬件体系结构:包含输入/输出设备、存储器、中央处理器【运算器,控制器】。所有的设备都是围绕存储器工作的,存储器是所有设备之间的一个缓冲带。
存储器

  • 内存(吞吐量更高,但断电后数据丢失)
  • 硬盘(不会丢失)
操作系统

核心功能:统筹管理计算机上的软硬件资源,管理(仅管理信息)先描述再组织。
作用:操作系统向上系统调用接口向下通过硬件驱动程序管理多个硬件。

进程

概念:进程就是一个运行中的程序,由于操作系统将运行中的程序描述起来,所以进程通过描述信息控制程序的运行。

程序:高级语言代码–>编译后的机器二进制代码

描述信息就是操作系统调度一个程序运行的实体,所以操作系统中进程就是运行中程序的描述——pcb【进程控制块】
操作系统通过pcb控制管理程序的运行—linux下为结构体:struct task_struct{…}
结构体中包含:

  • 内存指针
  • 上下文数据
  • 程序记录器
  • 进程标识符(PID)【编号】
  • 进程状态
  • 进程优先级(交互式>===>程序优先分配)
  • 进程文件状态信息
  • 记账信息(cpu在各程序上运行时间,以动态调整)

cpu分时机制:让cpu在每一个程序上只运行很短的一段时间(时间片),切换下一个程序处理,给人多个程序同时运行的假象。
查看当前操作系统中所有进程信息:

ps -aux #更详细
ps -ef

创建进程:pid_t fork()在内核中创建一个task_struct结构体,子进程结构体中会复制父进程结构体中所有信息,实现父子进程代码共享,数据独有。
注意: 使用pid_fork()创建,返回值<0:创建失败;,返回值==0:子进程返回;返回值>0:父进程中返回子进程pid,子进程返回0,父进程返回子进程。

int main()
{
    pid_t pid = getpid();//获取当前进程pid
    pit_t child_pid=fork();//创建子进程
    int val=100;
    if(child_pid==0)
    {
       val=10;
       //输出10
    }else if(child_pid>0)
    {
        //输出100
    }

进程状态

进程状态:就绪、运行、堵塞。
linux下状态:

  • 运行状态:R 正在运行+就绪(拿到时间片就运行)
  • 可中断休眠状态 S
  • 不可中断休眠状态: D 只能等待条件满足后醒来
  • 停止状态:T 停止运行,什么都不做
  • 死亡状态: X
  • 僵死状态: Z
  • kill:杀死进程,kill 9:强杀

僵尸进程:子进程先于父进程退出,若父进程没有关注子进程退出状态,则子进程进入僵尸状态。子进程退出之后并没有完全释放资源,保存退出返回值(退出原因),操作系统检测到后会通知父进程,但父进程没有关注这个通知,所以操作系统无法直接释放子进程所有资源,子进程会进入僵死状态成为僵尸进程。
僵尸进程的危害:资源泄漏
如何处理:退出父进程
如何避免僵尸进程的产生:进程等待
nums/zombie/orphan/g :将第num行内容中zombie字符串替换成orphan字符串
num1,num2/zombie/orphan/g : 从num1到num2进行内容替换
孤儿进程
父进程先于子进程退出,则子进程会成为孤儿进程,运行于后台,被1号init进程领养。
守护/精灵进程:
是一个特殊的孤儿进程,完全独立的运行在系统后台,脱离终端的影响。(…d)

#include <unistd.h>
int main()
{
    pid_t pid = getpid();//获取当前进程pid
    pit_t child_pid=fork();//创建子进程
    if(child_pid==0)
    {
        //子进程
    }else if(child_pid>0)
    {
        //父进程
    }
    while(1)
    {
        printf("-------%d---fpid---\n",getpid(),pid);
    }
    return 0;
}

关于创建进程:可以通过返回值对父子进程的运行进行分流,让其各自运行一段代码

**优先级:**决定cpu优先分配权的等级,让操作系统运行更良好。
nice/renice PRI=PRI+NI,nice值越高,PRI越高,优先级越低,设置nice值:

nice -n
renice -n -p pid

按性质划分程序:交互式和批处理

环境变量

保存系统运行环境参数的变量(仅当此生效)
作用:配置系统运行环境参数可以使系统配置起来更加灵活;可以通过环境变量给一个进程传递参数【环境变量具有全局性,可以由父进程传递给子进程】
操作命令:

  • env:查看所有的环境变量
  • set:查看所有变量
  • echo:直接打印指定变量的值
  • export:声明一个环境变量
  • unset:删除一个变量
int main(int argc,char*argc[],char*env[])
#                    程序运行参数  环境变量
{
    int i;
    for(i=0;i<argc;i++)
                printf("argc[%d]==%s",i,argc[i]);
}
MYVAL=1000
echo $PATH
echo ${PATH}
export MYVAL

./env|greap MYVAL

典型的环境变量
PATH:程序运行的默认搜索路径
SHELL/USER/PWD/HOME…
获取环境变量:
int main(int argc,charargc[],charenv[])
extern char environ //全局变量
char
getenv(const char
name) //名称获取
创建一个进程,子进程可以获取到所有的环境变量。
设置环境变量:
putenv/setenv

程序地址空间
进程的虚拟地址空间(程序不占内存,运行产生进程后才有地址)。主要通过页表映射访问不连续的内存空间。因为直接访问物理内存,进程之间内存访问缺乏控制,内存的利用率低。

内存地址:内存区域的编号

在程序中看到所有地址都是虚拟的,程序地址空间是一个虚拟地址空间。

操作系统为用户虚拟了一个完整的、连续的地址空间mm_struct,避免用户直接操作物理内存。
如何将虚拟地址映射转换为物理地址
1.分段式内存管理
内存地址:段号+段内偏移
段表内获取 物理内存段起始地址—>物理地址
对程序编译时内存管理更加友好
2.分页式内存管理
内存地址:页号+页内偏移
物理块号
主要用于提高内存利用率
实现:
3.段页式内存管理
将程序地址空间进行分段式管理,但在每个段内进行分页式管理
内存地址:段号+段内页号+页内偏移
实现:

每个进程都有自己独立的虚拟地址空间,访问的都是虚拟地址、通过页表将虚拟地址映射到物理内存地址,进而访问物理内存区域实现了物理内存的离散式存储
通过页表映射转换实现了数据在物理内存中的离散式存储—提高了内存利用率。
通过页表中进行访问限制,实现内存访问的控制。
每个进程都有自己独立的虚拟地址空间,访问的是自己的虚拟地址,因此进程间具有独立性。
进程调度算法:大O(1)调度算法[多级反馈]

进程控制:

进程创建 - 进程终止 - 进程等待 - 程序替换
进程创建:
pid_t fork(void)
流程:1.创建pcb 2.复制信息 (clone())3.内存数据发生改变时为子进程重新开辟空间,拷贝数据(写时拷贝技术)
pid_t vfork(void)—创建子进程,父子进程公用同一个虚拟地址空间,使用同一个栈会造成调用栈混乱。
创建子进程的存储:

因此父进程调用vfork创建子进程,会被阻塞,直到子进程exit退出/进行了程序替换,重新创建了自己的虚拟地址空间后,父进程才会vfork返回继续运行。return退出会释放虚拟内存空间。
进程终止
进程退出的场景:

  • 正常退出,结果符合预期
  • 正常退出,结果不符合预期
  • 异常退出,结果不能作为判断标准
#include<string.h>
//int error;      保存每次系统调用错误编号
//perror(char* info)   打印错误信息在info之后
//strerror(i);       根据给定的errno获取错误描述信息
int main()
{
    for(int i=0;i<133;i++)
   { 
       printf("%d"---"%s",i,strerror(i));
   }
}

进程的返回值仅用了一个字节保存
1.main()函数中的return //数据写入文件
2._exit(int state)系统调用接口,二号手册 man 2 exit //直接释放缓冲区
3.exit(int state) 库函数, 三号手册 man 3 //数据从缓冲区写入文件


pid_t pid=vfork();
if(pid==0)
{
    //子进程;
    printf("child");
    exit(99);//打印child
    //_exit(99);//不打印直接退出
}else
{
    //父进程;
}

进程等待:
等待子进程退出,获取子进程的返回值,允许操作系统释放子进程资源,避免产生僵尸进程。
如何等待:pid_t wait(int *status) 等待任意一个子进程退出,通过status获取返回值,释放子进程资源,退出返回子进程的pid.【阻塞函数】
pid_t waitpid(int pid,int *status,int options);
pid>0:等待指定子进程;-1:等待任意一个子进程
options:0:默认阻塞等待子进程退出;WNOHANG:非阻塞
返回值=0表示当前没有子进程退出,-1出错

int status;
while(waitpid(pid,&status,WNOHANG)==0)
{
    #做其他事情并不断判断子进程是否释放
    ....
    sleep(2);
}
printf("%d",status);
#do....

这两个wait并不是子进程退出的时候才能去回收,而是只要已经有退出的子进程就可以去回收。
【阻塞:为了完成一个功能发起调用,但是当前不具备完成功能的条件,则一直挂起,直到条件满足功能条件后返回】
【非阻塞:为了完成一个功能发起调用,但是当前不具备完成功能的条件,则立即报错返回】
返回值的获取:

只有进程正常退出时,获取返回值才有意义
判断是否正常:通过status数据的低7位是否为0,若为0,正常退出
返回值:存储在status中低16位中高八位

获取异常退出信号值:status&0x7f
获取程序退出返回值:(status>>8)&0xff
WIFEXITED(status)-判断是否正常退出
WEXITSTATUS(status)-返回值

if(!(status&0x7f))
{
    (status>>8)&0xff;
}
if(WIFEXITED(status))
{
    WEXITSTATUS(status);
}

程序替换
替换一个进程正在运行的程序
在一个进程中,可以先将另一端程序加载到内存中,将自己的页表映射到新的程序位置,初始化pcb中
的虚拟地址空间中的代码段和数据段信息
int exevce(char* filename,char* argv[],char* env[])
filename:新的程序代码文件名称(带路径的文件名)
argv:新程序运行参数信息
env:新程序环境变量信息 成功->运行新程序;失败->返回-1
替换过程:

int execl(char* path,char* arg,…)//需要新程序的路径
int execlp(char* file,char* arg,…)//只需文件名(去PATH指定路径找程序)
int execle(char* path,char* arg,…char*env[])//env:为新程序指定环境变量

int execv(charpath,charargv[])
int execvp(char* file,char* argv[])

自主实现minishell,完成shell基本功能
换行输入到标准输入缓冲区
fgets–标准输入缓冲区获取(包括换行)

#include<ctype.h>
#include<sys/wait.h>

int main()
{
while(1)
{
    //输入
    fflush(stdout);
    char buf[1024]={0};
    fgets(buf)
    buf[strlen(buf)-1]='\0';//将换行符换为结尾标志
    
    
    //字符串解析
    char* prt=buf;
    char* argv[30]={NULL};
    int argc=0;
    while(*ptr!='\0')
    {
        if(!isspace(*ptr))
        {
            argv[argc++]=ptr;
            while(*ptr!='\0'&&!isspace(*ptr))
            {
                *ptr='\0';
            }
            ptr++;
        }
        argv[argc]=NULL;//最后一个参数以NULL结尾
        
        
        pid_t pid=fork();
        if(pid==0)
        {
            execvp(argv[0],argv);//子进程进行程序替换
            exit();
        }
        waitpid(pid,NULL,0);//阻塞等待子进程
    }
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值