Vue框架:Vue驾校-从项目学Vue-1
算法系列博客友链:神机百炼
查看单一进程指令:
ps aux | head -1 && ps aux | grep 进程名
进程PCB信息:

关注点:PID + STAT + COMMAND
process文件夹:
ls /proc/
查看所有进程:

以上所有蓝色数字就是PID,查看单一进程更多信息:
ls /proc/对应进程的pid //大致信息
ls /proc/对应进程的pid -al //详细信息
单一进程大致信息:

单一进程详细信息:

PS:linux文件类型
| 符号 | 含义 | 作用 |
|---|---|---|
| - | 普通文件 | |
| d | 目录文件 | |
| c | 字符设备文件 | 外设驱动 |
| b | 块设备文件 | 外设驱动 |
| l | 符号链接文件 | 快捷方式—指向另一文件/文件夹 |
| s | 套接字文件 | |
| p | 管道文件 |
PS:权限:
linux文件的用户分三类:owner编写者 + group同组员 + others陌生人
linux文件的权限有三种:r读取 , w写入 , x运行 , -无权限
三位二进制权限:rw-为110 ,r–为100
对于d文件夹:ls为r ,touch为w ,cd为x
PS:用户权限更改:
chmod u/g/o +/- rwx 文件名
用户 增删 权限
PS:粘滞位更改删除权限:
chmod +t 文件名 //设置粘滞位t防止同group删除文件
PS:权限掩码umask
假设二进制权限为110 110 110
权限掩码umask为 001 001 001
最终权限为:umask取反后 与 初始权限 ,即还是110 110 110
先回顾一下什么叫创建进程:
初学进程时的概念就是程序运行起来就是进程
./文件名.文件后缀
创建进程的系统调用接口
#include
pid_t fork(void);
//fork()有两个返回值:一会输出看看
//为父进程返回子进程的pid
//为子进程返回0
在代码中创建子进程,同时查看其pid & ppid:

gcc 编译+ ./运行:

结论:
想要创建子进程,父进程必须在运行
fork之前的代码,只有父进程执行
fork之后的代码,父子进程都在执行
fork之后的代码,父子进程谁先被执行取决于进程调度算法,先后顺序不定
所有进程由父进程创建,可以构成一颗多叉树
硬件层面:子进程共享父进程数据和代码

代码:

结论:fork()有两次/两个返回值

第一次为父进程返回的是创建的子进程的pid
第二次为子进程返回0
应用:
利用不同的返回值,让父子进程同时执行不同的代码,也就是if else可以同时执行了:
#include
#include
int main(){
printf("I am running...\n");
pid_t id = fork();
if(id == 0){ //子进程任务
while(1){
printf("child process\n");
sleep(1);
}
}else if(id > 0){ //父进程任务
while(1){
printf("parent process\n");
sleep(2);
}
}else{ //fork调用失败时返回负数
while(1){
printf("failed process\n");
sleep(1);
}
}
}
关于fork的软硬件细节,在《进程控制》中详细展开
结束进程的系统调用接口:
#include
void exit(int status); //status传递1即可
使用:
#include
#include
#include
int main(){
pid_t id = fork();
if(id == 0){
for(int i=0; i<5; i++)
printf("这是子进程\n");
printf("退出子进程\n");
exit(1); //进程退出
}else if(id > 0){
while(1){
printf("这是父进程\n");
}
}
return 0;
}
对于所有类型操作系统,宏观上的进程状态理解:

linux将不同的进程状态通过宏定义,数字化表示
且进程状态STAT信息存储在PCB/task_struct{}当中

含义:R状态虽然写作running,但是其实是“就绪”,并非“运行中”
所以很多PCB进程块可以同时表示自己已经R,等待被CPU调度
调度队列:

调度算法:父进程创建子进程后,执行顺序由调度队列的调度算法决定
含义:进程在等待其他事件就绪,称为浅度睡眠,该进程随时可以被唤醒也可以被杀掉
出现情况:
典型情况:

查看进程状态:

含义:磁盘休眠状态 / 深度睡眠deep sleep
区别于直接sleep,D状态的进程除非自己结束,谁也不能kill该进程
设立D状态的目的同样也是为了等待其他事件的就绪或者说发生
当PCB队列非常长的时,OS是可以kill掉S状态的进程的,但是不能kill掉D状态进程
含义:暂停进程
测试用例:

查看此时进程状态:s

kill -l 查看Linux支持的所有信号集:
可以通过kill命令向目标进程发送上述64条命令(1~31条是重点)
向进程发送STGSTOP信号:
kill -STGSTOP 28427
再看该进程的状态:T

与休眠的区别:
结束暂停信号:开始继续运行
kill -STGCONT 28427
Z zombie僵尸状态:
进程退出后,OS还保留着他曾申请的资源,供其父进程/OS读取
X dead死亡状态:
进程退出后,OS读取完他曾申请的资源后(一定要有人读取完才能释放),释放这些曾用过的资源
为什么要有僵尸状态:
创建进程是为了解决问题,问题是否解决就看数据是否处理完成
进程结束后,数据拿给父进程/OS检查一下,才能知道进程的任务完成的好不好
典型的僵尸状态的应用:
#include
int main(){
//任务代码
return 0;
}
main函数的调用关系:
退出码$:
命令行中,最近一次进程退出时return的数据称为退出码:

echo $? //$即退出码,此处打印11
进程退出的相关信息:
进程退出后,保留的相关消息有很多,不只$退出码,当然这些都保存在了PCB结构体属性中
查看/读取退出相关信息:
等到《进程控制》博客,再来展开
查看僵尸状态:
检测进程状态脚本:
while :; do ps aux | head -1 && ps aux | grep myproc | grep -v grep;echo "##################################"; sleep 1; done
//##################################是自己设置的行分割符
创建进程:myproc.c
#include
#include
#inclued <stdlib.h>
int main(){
pid_t id = fork();
if(id == 0){
for(int i=0; i<5; i++){
printf("I am child process. pid:%d ppid:%d %d\n", getpid(), getppid(), i);
sleep(1);
}
printf("child quit\n");
exit(1);
}else if(id > 0){
while(1){
printf("I am father. pid:%d ppid:%d\n", getpid(), getppid());
sleep(1);
}
}else {
printf("failed child process\n");
}
return 0;
}
查看进程状态:

僵尸进程:
子进程直接退出,进入Z状态,等待父进程读取其退出信息后,子进程正式死亡
孤儿进程:
父进程直接退出,父进程进入Z状态,等待父进程的父进程读取其信息,将其死亡
此时子进程还在运行,进入了**“孤儿进程状态”**,父进程已经退出,那么谁来回收子退出时的退出信息呢?
如果孤儿进程的僵尸资源没有人回收,那么造成了经典内存泄漏问题
孤儿进程会被OS领养,其退出时的僵尸资源被OS读取和释放,让孤儿僵尸进程彻底死亡
举例:父进程先退出:
#include
#include
#inclued <stdlib.h>
int main(){
pid_t id = fork();
if(id == 0){
while(1){
printf("I am child. pid:%d ppid:%d\n", getpid(), getppid());
sleep(1);
}
}else if(id > 0){
for(int i=0; i<5; i++){
printf("I am father. pid:%d ppid:%d %d\n", getpid(), getppid(), i);
sleep(1);
}
printf("father quit\n");
exit(1);
}else {
printf("failed child process\n");
}
return 0;
}
脚本查看父子进程状态:
while :; do ps axj | head -1 && ps axj | grep myproc | grep -v grep; echo "################################" ; sleep 1; done;
查看孤儿进程状态:ppid==1

