网站通知做文献的格式,莱芜话题最新消息,大学生电商创业项目,北京百度seo点击器#x1f57a;作者#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 #x1f618;欢迎关注#xff1a;#x1f44d;点赞#x1f64c;收藏✍️留言 #x1f3c7;码字不易#xff0c;你的#x1f44d;点赞#x1f64c;收藏❤️关注对我真的… 作者 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 欢迎关注点赞收藏✍️留言 码字不易你的点赞收藏❤️关注对我真的很重要有问题可在评论区提出感谢阅读 文章目录 前言进程基本概念描述进程-PCBtask_struct-PCB的一种task_ struct内容分类 组织进程查看进程通过系统调用获取进程标示符通过系统调用创建进程-fork初识1. 父子进程代码共享数据各自开辟空间私有一份采用写时拷贝。2. 父进程先运行还是子进程先运行3. 创建子进程时OS要做什么 后记 前言
本篇我们将正式进入Linux的世界首先先要讲的就是进程进程是什么怎么描述如何组织、查看如何创建本篇都将详细讲解~
进程基本概念
课本概念程序的一个执行实例正在执行的程序等
实际上我们启动一个软件的本质上就是启动了一个进程在Linux系统中运行 ./a.out 时其实就是在系统的层面上创建了一个进程如下
#include stdio.h
#include unistd.h
int main() { while(1) { printf(hello world!\n); sleep(1); } return 0;
} 内核观点担当分配系统资源CPU时间内存的实体。
从内核观点看的话就是如下图这样后面再讲概念。
按照之前操作系统篇讲过的先描述再组织所以可以预言系统中会存在一个管理对应进程的结构体因为不同的进程的属性不同不可能直接管理进程只能通过一个结构体来管理它这个结构体的内容应该包括该进程的各个属性我们之后叫它PCBprocess control block当然不同的系统中的叫法可能不同但是理念是一样的。
区分程序和进程 程序的本质是一个静态文件存储在磁盘中 进程是对应的代码数据进程对应的PCB结构体
描述进程-PCB
进程信息被放在一个叫做进程控制块的数据结构中可以理解为进程属性的集合。 课本上称之为PCBprocess control blockLinux操作系统下的PCB是: task_struct
task_struct-PCB的一种
在Linux中描述进程的结构体叫做task_struct。 task_struct是Linux内核的一种数据结构双向链表它会被装载到RAM(内存)里并且包含着进程的信息。
task_ struct内容分类 进程标示符: 描述本进程的唯一标示符用来区别其他进程。
进程PID是在当前操作系统中唯一标识一个进程的标识符。
ps aux命令可以查看当前操作系统中所有的进程信息 进程状态: 任务状态退出代码退出信号等。 进程状态 三种状态 运行态正在拿着CPU资源进行运算的进程所持有的状态 就绪态一切的准备资源都准备就绪了等待操作系统分配CPU资源 阻塞态等待某种资源到来之后才能进行运算 细分状态 R运行状态 S可中断睡眠状态意味着进程在等待事件完成 D不可中断睡眠状态有时候也叫不可中断睡眠状态uninterruptible sleep在这个状态的进程 通常会等待IO的结束。 T暂停状态可以通过发送 SIGSTOP 信号给进程来停止T进程。这个被暂停的进程可以通过发 送 SIGCONT 信号让进程继续运行。 t跟踪状态当进程被gdb调试时会产生t X死亡状态这个状态只是一个返回状态你不会在任务列表里看到这个状态 Z僵尸状态一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就 会产生僵死(尸)进程 进程优先级: 相对于其他进程的优先级。 程序计数器: 程序中即将被执行的下一条指令的地址。 内存指针: 包括程序代码和进程相关数据的指针还有和其他进程共享的内存块的指针 上下文数据: 进程执行时处理器的寄存器中的数据。 IO状态信息: 包括显示的I/O请求,分配给进程的IO设备和被进程使用的文件列表。 记账信息: 可能包括处理器时间总和使用的时钟数总和、时间限制、记账号、cpu使用率、内存使用率、CPU使用时长。 其他信息
组织进程 可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。 查看进程
进程的信息可以通过 /proc 系统文件夹查看 如要获取PID为1的进程信息你需要查看 /proc/1 这个文件夹。 大多数进程信息同样可以使用top和ps这些用户级工具来获取 #include stdio.h
#include sys/types.h
#include unistd.h
int main() {while(1){ printf(hello world!\n);sleep(1);} return 0;
}
ps aux | grep mycode | grep -v grep通过系统调用获取进程标示符 进程idPID父进程idPPID 返回0为子进程返回大于0子进程PID为父进程返回小于0创建失败 #include stdio.h
#include sys/types.h
#include unistd.h
int main()
{printf(pid: %d\n, getpid());printf(ppid: %d\n, getppid());return 0;
}通过系统调用创建进程-fork初识
1. 父子进程代码共享数据各自开辟空间私有一份采用写时拷贝。 代码是逻辑一般不可被修改数据即可读又可写。 进程是有独立性的父子进程fork完毕后谁先运行是不确定的这个有调度器决定。
测试代码
#include stdio.h
#include sys/types.h
int main(int argc, char *argv[]) {printf(begin fork...\n);fork();printf(end fork...\n);return 0;
}
结果出现两个end fork… 测试代码
#include stdio.h
#include sys/types.h
int main(int argc, char *argv[]) {printf(create process failed\n);pid_t pidfork();if(pid0){printf(create process failed\n);}else if(pid 0){ printf(create child success\n);}else{ printf(create parent success\n);}printf(end fork...\n);return 0;
}
结果 pid进入两个分支说明了有两个pid值也就说明fork有两个返回值
为什么会有两个返回值
因为fork内部父子各自会执行自己的return语句返回两次并不意味着缓存两次。以后讲
return后核心代码都执行完了吗
完成了
fork函数是怎么新建进程的
操作系统和CPU运行某个进程本质就是从task_struct链表中挑一个task_struct来执行它的代码只要想到进程就要优先想到对应的task_struct而进程调度就变成了在task_struct链表中选择一个进程的过程fork函数就是再创建一个进程和task_struct并将这个task_struct添加到task_struct队列中。
为什么给子进程返回0父进程返回子进程的pid感性分析一下并不完全正确
子进程只有一个父进程而父进程可以有多个子进程fork之后给父进程返回子进程的pid可以方便父进程对子进程进行管理而父进程对子进程是唯一的子进程只需要知道自己是否创建成功成功创建后的父进程是谁即可。
既然子进程有父进程那最终的父进程是谁
是bashbash是所有进程的父进程验证如下 子进程的ppid是父进程的pid而父进程的ppid是bash所以bash是所有进程的父进程。 代码
#includestdio.h#includeunistd.hint main(){ int retfork();if(ret0){ printf(fork error!\n);} else if(ret0){ printf(i am child:%d ret%d\n,getpid(),ret);} else{ printf(i am parent:%d ret%d\n,getppid(),ret);} return 0; }
运行结果 查看
ps aux | grep 321582. 父进程先运行还是子进程先运行
子进程在被创建后在内核中会生成一个PCB对它进行管理这个PCB会被挂在PCB构成的双向链表当中组织起来而父进程与子进程谁先运行是不确定的取决于操作系统的调度它是抢占式执行的也就是OS会给进程运行一段时间然后中止把CPU资源让给其他进程。子进程在创建出来以后子进程的运行与父进程无关了
3. 创建子进程时OS要做什么
本质上就是新建了一个task_struct加入到系统中 后记
本篇主要讲述了进程的基本概念以及如何描述进程——PCB并且讲述了如何通过系统调用获取进程标识符如何创建子进程——初识fork更为深入的讲解将在后面的文章进行讲述~