文章目录

  • 进程创建
    • fork函数
    • 用户空间、内核空间
    • 写实拷贝
    • fork创建子进程时的一些特性
    • 守护进程
  • 进程终止
    • 正常终止
    • 异常终止
    • exit和_exit的区别
    • 缓冲方式

进程创建

fork函数

调用fork函数让正在运行的进程创建出来一个子进程。得到的新进程为子进程,而原进程为父进程。

pid_t fork(void)

fork函数有两个返回值,如果创建成功,那么返回给父进程一个大于0的值,即子进程的进程号,返回给子进程数字0,如果创建失败,那就给父进程返回-1,父子进程是独立的进程,fork分别在父子进程当中进行返回,由于父子进程返回不同的值,且相互独立,我们可以通过返回值来让父子进程执行不同的代码。
我们来简单看一下正在运行的父进程创建子进程的代码,试验一下:

运行结果:

观察数字,我们可以给出一个经验,一般来说,子进程的pid比父进程小1。

fork内部完成的事情:

  • 创建子进程,子进程拷贝父进程的PCB
  • 分配新的内存块和内核数据结构(task_struct)给子进程
  • 将父进程部分数据结构内容拷贝给子进程
  • 添加子进程到系统进程列表当中,添加到双向链表里当中
  • fork返回,操作系统开始进行调度,调度的时候遵循以下原则:先来先服务、短作业优先、优先级优先、时间片轮转等

用户空间、内核空间

内核空间:Linux操作系统和驱动程序运行在内核空间。系统调用的函数都是运行在内核空间的,因为是操作系统提供的函数。
用户空间:应用程序都是运行在用户空间的,应用程序属于程序员自己写的代码,程序员自己写的代码都是运行在用户空间的。
当程序员写的代码中调用了系统调用函数,就会从用户空间切换到内核空间去执行系统调用函数,执行完之后再次回到用户空间继续执行程序员写的代码。

写实拷贝

fork创建子进程的时候,子进程会拷贝父进程的PCB,页表也会拷贝父进程的。所以同一个变量的的虚拟地址和物理地址的映射关系在父进程和子进程中是一样的,也就是说,操作系统并没有给子进程当中的变量在物理内存当中分配内存空间进行存储,子进程的变量还是父进程的物理地址当中的内容。

当子进程中的变量发生改变时,才会以写实拷贝的方式进行拷贝,也就是分配物理内存,此时父子进程通过各自的页表,指向不同的物理地址。
当子进程中的变量不发生改变时,父子进程共享一个数据,这样子有一个明显的好处就是节省内存空间。

执行结果:

fork创建子进程时的一些特性

  • (进程独立性)父子进程相互独立,互不干扰。各自有各自的进程虚拟地址空间和映射页表,不能访问对方的数据
  • 父子进程独立被操作系统调度,父子进程是抢占式执行,父子进程先后执行顺序本质是由操作系统调度决定的,不过进程自身情况也会影响执行先后顺序
  • 子进程是从fork之后开始运行
  • 代码共享,数据独有

守护进程

父进程创建子进程,通过进程程序替换,让子进程执行真正的业务,父进程负责守护子进程,子进程和父进程之间进行进程间通信,当父进程检测到子进程异常的时候,父进程就会重新启动子进程(再创建一个子进程),让子进程继续提供服务。
守护进程是提高“高可用”的一种手段。

进程终止

进程终止有两种场景,正常终止和异常终止。
正常终止又有两种情况:代码运行完毕,完成了既定的代码功能;代码运行完毕,但是没有完成既定的功能。

正常终止

可以通过命令“echo $?”查看进程退出码

正常终止有下面三种情况:

  • 1、从main函数的return返回

我们查看一下进程退出码:

这种情况下,进程退出码就是return返回的值,我们修改一下return后面的值,就会发现进程退出码也会改变。

查看一下进程退出码:

  • 2、调用exit函数(库函数)

调用exit函数之后,就会直接退出进程了,所以上面的代码查看进程退出码就是2不是1了,因为后面的打印和return 0 都不会执行。

  • 3、调用_exit函数(系统调用函数)

异常终止

  • 1、解引用空指针,解引用野指针(垂悬指针)

    执行结果:

    产生了段错误,进程异常终止,此时会产生一个核心转储文件,我们来看一看:

    看不到核心转储文件,这是为什么呢?因为core file size的-c的位置是0,有限制,我们修改一下:

    现在就能产生核心转储文件了,再执行一次,就能看到产生的核心转储文件了。

    我们看一下这个coredump文件的这个段错误的信息:
  • 2、double free

对一块空间释放两次,会引起进程的异常终止,也会产生coredump文件。

执行产生了错误:

  • 3、内存访问越界

进程内存访问越界的时候,会被操作系统强杀。

exit和_exit的区别

exit函数_exit函数两者最大的区别就是exit函数会比_exit函数多了两个步骤:执行用户定义的清理函数、冲刷缓冲,关闭流等。

  • 1、执行用户自定义的清理函数

void (*function)(void) 这是一个函数指针

指针函数:本质是一个函数,返回值是指针,也就是说,指针函数就是返回值为指针的函数。
函数指针:本质是一个指针,指向代码段中函数入口地址,(*function) 是一个整体,代表的是指向该函数的指针,(function) 是函数指针变量,函数名就是函数的入口地址,所以函数指针变量就是函数名。

atexit是注册函数指针保存的函数地址到内核当中去,注册这个函数并不是调用这个函数。所以下面这段代码中,atexit注册了atexit_callback函数,但是并没有调用执行,而是在整个进程结束之后,进行回调,所以才有了这样子的执行结果。

4 void atexit_callback(){                                                                        5   printf("I am atexit_callback,hhhh.\n");6 }7 int main(){8   atexit(atexit_callback);9   printf("hello world.\n");10   return 0;11 }

执行结果:

当程序达到了某种固定的场景的时候,会进行回调,调用的函数被称为回调函数。

  • 2、刷新缓冲区
printf("hello world.\n");

“hello world”并不是直接被打印到屏幕上面的,而是先被放入缓冲区,再刷新缓冲区到屏幕上。

换行符可以刷新缓冲区、从main函数的return返回可以刷新缓冲区、exit函数、fflush函数(强制刷新缓冲区)这几种方式都可以刷新缓冲区。

#include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 int main(){5   printf("hello world");6   fflush(stdout);                                                                              7   _exit(2);8   int count = 5;9   while(count){10     sleep(1);11     count--;12   }13   return 0;14 }

缓冲方式

  • 全缓冲:缓冲区写满再进行IO
  • 行缓冲:输入和输出遇到换行符的时候,标准I/O库执行I/O操作,也就是说,一行写满就进行刷新。
  • 不缓冲:不带缓冲,标准I/O库不对字符进行缓冲存储,也就是说放入缓冲区后立即就刷新出来。

【Linux】进程控制1-进程创建、进程终止相关推荐

  1. Linux系统编程15:进程控制之如何创建进程和写时拷贝技术

    文章目录 (1)fork函数回顾 (2)写时拷贝 (1)fork函数回顾 在下面这篇文章我们演示了fork函数以及相关细节 点击跳转 还是借助上文中的程序和效果图片 #include <stdi ...

  2. Linux C : 进程管理实验:创建进程、上下文切换

    进程可以看成程序的执行过程,可以展示在当前时刻的执行状态.它是程序在一个数据集合上的一次动态执行的过程.这个数据集合通常包含存放可执行代码的代码段,存放初始化全局变量和初始化静态局部变量的数据段.用于 ...

  3. 【CSAPP】进程控制 | 系统调用错误处理 | 进程状态 | 终止进程 | 进程创建 | 回收子进程 | 与子进程同步(wait/waitpid) | execve 接口

  4. php 父进程id,PHP pcntl_fork创建进程,复制父进程内存空间上下文

    /** * Created by PhpStorm. * User: Sixstar-Peter * Date: 2019/2/28 * Time: 21:02 */ $a=1; $ppid=posi ...

  5. Linux——进程控制:创建、终止、等待、替换

    进程创建 fork #include <unistd.h> pid_t fork(void); 操作系统做了什么? 调用fork之后,内核的工作: 分配新的内存块和内核数据结构给子进程 将 ...

  6. 模拟进程创建、终止、阻塞、唤醒原语_操作系统基础8-进程及进程控制

    进程(Process) 的定义 从不同的角度,进程可以有不同的定义,传统典型的定义: 进程是程序的一次执行过程. 或者:一个正在执行的程序的实例 进程是一个程序及其数据在处理机上顺序执行所发生的活动 ...

  7. Linux进程的创建图文教程,进程的创建和终止(超详细)

    大多数系统的进程能够并发执行,它们可以动态创建和删除.因此,操作系统必须提供机制,用于创建进程和终止进程. 进程创建 进程在执行过程中可能创建多个新的进程.创建进程称为父进程,而新的进程称为子进程.每 ...

  8. 操作系统原理,进程的基本状态,运行态,就绪态,等待态与转换模型,进程的其他状态,创建,终止,挂起与转换模型,Linux进程状态模型示例

    操作系统原理,进程的基本状态,运行态,就绪态,等待态与转换模型,进程的其他状态,创建,终止,挂起与转换模型,Linux进程状态模型示例 一.进程的三种基本状态: 运行态,就绪态,等待态 1.运行态: ...

  9. vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制

    Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...

最新文章

  1. eval语法报错 ie10_js eval 语法错误 急急急
  2. 在北京植物园吸烟将被机器人劝阻
  3. Impala性能优化
  4. c++ doxygen 注释规范_C语言代码注释参考
  5. 科学计算机简单编程_是“计算机科学”还是“编程”?
  6. c++位运算_最全位运算总结
  7. SRM 207 Div II Level Two: RegularSeason,字符串操作(sstream),多关键字排序(操作符重载)...
  8. 拓端tecdat|R语言rcurl抓取问财财经搜索网页股票数据
  9. 内嵌网页 UniWebView 3 的使用
  10. linux驱动与windows驱动精灵,细说驱动精灵和驱动人生哪个好
  11. jsoneditor光标错位的原因及解决方式
  12. 管螺纹如何标注_你所不知道的机械螺纹全面常识(分享篇),赶紧收藏下吧
  13. JS - 解决鼠标单击、双击事件冲突问题(同时实现两种事件响应)
  14. 翻译《有关编程、重构及其他的终极问题?》——13.表格化的格式化
  15. ubuntu下运行.exe程序
  16. python 删除pdf页面_删除PDF其中几页的方法
  17. 2个DIV制作十字架
  18. 验证身份证是否真实有效
  19. 产品生命周期管理——高效的全生命周期的产品管理方法
  20. ▷Scratch课堂丨物理模拟地球公转,值得你的分享收藏!

热门文章

  1. 隆云通土壤温湿、EC、PH、氮磷钾传感器
  2. 随机生成不重复的字符和数字
  3. Xamarin.Android开发及常见问题的解决
  4. nginx 静态资源文件映射
  5. 高中数学必修四:平面向量知识点(基本概念)
  6. WiFi标志消失,无线网卡驱动无法启动
  7. linux查看无线网卡漫游,在Linux中漫游用户配置文件
  8. QT大作业——自制小游戏
  9. 面膜系统是什么模式?康皱面膜系统模式是什么原理,有什么作用
  10. 腾讯云的使用(创建存储桶)。