Linux:进程概念和进程控制

目录

文字概念:

进程创建:

进程等待,处理僵尸进程:waitpid()

程序替换:

编写minishell程序了解进程替换:​​​ 

文字概念:

操作系统:对计算机软硬件资源进行管理的软件

系统调用:操作系统向用户提供的用于访问内核的接口.

程序:程序就是程序员写的代码,指令集.

进程:操作系统的角度进程就是进程控制块pcb,在linux下是task_struct结构体.

进程控制块pcb:程序运行的动态描述,包含程序运行的各项信息 如标识符pid,内存指针,程序计数器,  上下文数据,进程状态,进程优先级,io信息,记账信息等.

进程状态:就绪,运行,阻塞三大类.

linux下分为 : 运行态 -R:正在运行的,以及拿到时间片就能运行的.

可中断休眠态 -S:可以被打断的阻塞状态.

不可中断休眠态 -D:顾名思义.

停止态 -T:停止运行.

 僵尸态 -Z : 程序退出后等待父处理的状态 .  僵尸进程就是僵尸态的进程,退出后资源没有完全被释放的进程,是因为子进程先于父进程退出,为了保存自己的退出的返回值等待父进程处理返回值,等待过程就没完全释放资源.

避免方法:由于僵尸进程会导致资源泄漏我们要尽量避免产生僵尸进程进程等待,wait,waitpid方法.

处理 : 退出父进程,kill命令对僵尸进程没用.(kill pid)

演示:

孤儿进程:  父进程先于子进程退出,子进程就变成了孤儿进程,1号进程成为子进程的父进程.

孤儿进程不占据当前程序运行的会话,在后台运行(当前会话能打指令)

 1号进程(init)是负责任的进程,所以孤儿进程退出不会成为僵尸进程,可以被kill掉

孤儿进程设置了自己的会话空间后成为守护进程(精灵进程),会话空间是问号"?",脱离了终端运行.

演示:

 

查看进程信息的指令:ps -ef或ps -aux,通常配合grep使用:ps -ef | grep "string" , 查找相关进程信息

创建进程:  pid_t fork(),通过复制父进程创建一个新的进程(即子进程),无参. 如果是父进程则父进程得到的返回值是子进程的pid,是子进程则为0,创建失败返回-1. 在调用fork后的子进程,父进程代码和数据一模一样. 通过返回值在代码中对父进程子进程要运行的代码分流.fork后子进程版留了父进程的环境变量和当前工作目录. fork创建子进程在内核中通过调用clone实现. 具有写实拷贝机制!子进程创建后有自己的虚拟地址空间,与父进程映射同一块物理内存,但是,如果内存中数据发生改变(父进程修改或子进程修改),则为子进程针对这 一要修改的内存另开辟空间拷贝数据过去.

                相关题目:

环境变量:保存程序运行环境参数等待变量,在进程之间传递数据(特性)

 env:查看所有环境变量  set:查看环境中所有变量  echo:打印指令变量的数据.

 export:设置环境变量.   unset:删除环境变量. 

shell中默认环境变量存放在~/.bash_profile中.

在程序中获取环境变量的接口:char *getenv(char *name);    name:环境变量名称.  返回值:对应name环境变量的数据,如果找不到返回NULL.

程序地址空间:程序地址空间,实际上是操作系统为进程通过mm_struct结构体(本质就是个结构体) 描述的虚拟的地址空间,让每个进程都能访问一个独立的完整的连续的虚拟地址,经过映射之后,实现在物理内存上的离散存储,提高内存利用率,提高了内存访问控制。通过内存管理单(MMU),S实现虚拟地址到物理地址的转换. 

程序中我们看到的地址都是虚拟地址,虚拟地址经过映射后存放在物理内存中.虚拟内存的管理方式:

分段式:将虚拟地址空间分为多个段(代码段,数据段等), 分段式的虚拟地址由段号和段内偏移组成.

分段式给每个进程创建一个段表,取出虚拟地址段号,通过段号找到某个段表项(段表项就是                段表中跟据段号不同 每个段号都有自己的一些信息,称为一项, 段表中的信息只有段号和物              理起始地址)根据找到的该项里的物理起始地址,加上段内偏移量得到某个变量的实际地址.

分页式:由页号和页内偏移组成 , 对应的也创建了页表 , 但是每个页号的对应的项有页号,权限位,缺页中断位,物理块起始地址.

分段式管理:将虚拟地址空间进行分段管理,对于内存利用率并没有太大提高,但是对于程序地址管理比较友好。
分页式管理:将虚拟地址空间划分成一个个小的页面进行管理,实现离散存储,提高了内存利用率,并且在页表中进行了权限管理,提高了内存访问控制.

段页式内存管理:将虚拟地址空间先进行分段管理,然后在每个段内进行分页式管理,集合了分段和分页的优点.  地址中包含:段号,段内页号,页内偏移
1.通过段号在段表中找到段表项. 2.在段表项中找到段内页表地址 3.通过段内页号在段内页表中找到页表项 . 4.通过页表项中的物理块起始地址加上页内偏移得到物理地址.

终止,退出一个进程exit()与_exit():

库函数exit与系统调用_exit的区别就在于:退出程序前是否会刷新缓冲区. 换行也会刷新文件缓冲区.
exit与return在退出程序前都会刷新缓冲区,将还没有写入文件的数据写入到文件中
_exit调用直接退出,不会刷新缓冲区,而是直接释放资源(有可能存在缓冲区中的数据丢失)

printf("hello"); sleep(3); 等待3秒后程序退出前打印;

printf("hello\n"); sleep(3); 直接打印hello,三秒后程序退出.

printf("hello"); _exit(0);不打印hello.

printf("hello\n"); _exit(0);打印hello.

printf("hello");exit(0);打印.

printf("hello\n");exit(0);打印.
return后边的数字和exit的参数status的作用:设置进程的退出码
退出码只保留低8位〔我们设置进程退出码尽量保持在0~255之间)       

进程创建:

        

进程等待,处理僵尸进程:waitpid()

(偷个懒)

 退出码int类型四个字节,如图.

waitpid(-1,&status,0)阻塞等待,等子进程退出了,waitpid处理了子进程,才向下进行代码,退出的子进程不会成为僵尸进程.和wait(&status)一样:

 (阻塞等待,等待子进程退出后再向下运行.)

waitpid(-1,&status,WNOHANG)不使用循环等待的话,子进程还没到退出时间,非阻塞等待就会直接向下进行代码,然后子进程再退出后就会变成僵尸进程:

(非阻塞等待,不等待子进程退出直接向下运行.没有子进程退出ret得到返回值0) 

waitpid(-1,&status,WNOHANG)使用循环等待,子进程退出不产生僵尸进程.常用写法*  :

值得注意的是如果,while里写的是6秒(即每6秒看子进程退出没,退出就处理没退出就再等6秒再看退出没),则此时5-6这一秒的之间内子进程将成为僵尸进程 . 6秒后再次waitpid处理子进程,就不是僵尸进程了.

程序替换:

通常很少替换当前进程调度的程序,而是创建子进程之后,替换子进程所运行的程序。

以前fork之后子进程与父进程干的事情相同,可以分摊压力(这种需求其实并不多),还有一种就是让子进程干其他的活,而干活逻辑都是在if(fork()==O)这个判断中完成,但是会导致代码庞大,不灵活。因此,若创建子进程之后,根据不同的工作,将子进程替换成为不同的程序,则代码模块则可以灵活很多。

常用的替换接口:

其他的替换接口:

下图是tihuan文件:

如果使用的运行参数是main默认的argv,那么 ./tihuan 算第一个参数,后面给的指令参数接着.

下图是exec_test文件. 

注意:程序替换函数如果替换成功,则这个函数调用之后的代码都不会被运行,因为程序已经被替换成为新的程序,而新的程序运行完毕之后,进程就退出了(不会返回回来运行原先的程序);

所以下面的execv success是不会打印的.

1.

 

2.

execl:

由于要求传入的参数和运行环境最后一个都要为NULL,所以像下面用传myargv的话在后面加一个NULL,然后env使用默认的.

或者是:int ret =execl("./tihuan","-a","-l",NULL);

 

 编写minishell程序了解进程替换:​​ 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux进程管理和进程通信是操作系统中非常重要的概念。我可以为您提供一些关于这两个主题的基本信息。 1. 进程管理: 在Linux中,进程是指在执行中的程序实例。进程管理包括创建、调度、终止和监控进程的活动。以下是一些关于进程管理的关键概念: - 进程标识符(PID):每个进程都有一个唯一的PID,用于标识和跟踪进程。 - 进程状态:进程可以处于运行、就绪、阻塞或终止等不同状态。 - 进程调度:操作系统根据特定算法决定哪个进程应该在给定时间内运行。 - 进程创建:通过fork()系统调用创建子进程,或者通过exec()系列系统调用加载新程序镜像并替换当前进程。 - 进程终止:进程可以自愿终止,或者由其他进程(如父进程或操作系统)强制终止。 - 进程监控:可以使用系统工具(如ps、top)或编程接口(如proc文件系统)来监控和管理进程。 2. 进程通信: 进程通信是指进程之间交换数据和信息的机制。在Linux中,有多种方法可以进行进程间通信,包括: - 管道(Pipe):用于在父子进程或具有亲缘关系的进程之间进行通信。 - 信号(Signal):用于向进程发送简单的通知或中断信号。 - 共享内存(Shared Memory):允许多个进程共享同一块物理内存,以便快速高效地进行数据交换。 - 消息队列(Message Queue):进程可以通过消息队列传递和接收消息。 - 信号量(Semaphore):用于实现进程间的互斥和同步操作。 - 套接字(Socket):适用于网络编程,允许不同主机上的进程进行通信。 这只是对Linux进程管理和进程通信的简要介绍,如果您有任何具体问题或深入了解的需求,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值