分享知乎上看到的一句话,共勉: 学习周期分为学习,思考,实践,校正四个阶段,周期越短,学习效率越高。

      前面讲的都是操作系统如何管理进程,接下来,看看用户如何进行进程控制。

    1.进程创建

      先介绍一下函数: pid_t fork(void);   返回值: 子进程返回0 父进程返回子进程id,创建子进程失败则返回-1       

        当一个进程调用fork后,就会产生两个二进制代码相同的代码。并且它们都运行到相同的地方。现在,给大家演示一下:

     

      

     由此,我们得到验证: fork之前父进程独立运行,fork之后,父子两个执行流分别执行。

    fork原理:       

          进程调用fork后,当控制权转移到内核的时候,内核会做四件事:

          1.分配新的内存块和数据结构给子进程

          2.将父进程部分数据结构拷贝给子进程

          3.添加子进程到系统进程(PCB)列表中

               4.fork返回,开始调度

      写时拷贝技术: 

      

      实际上fork就是给子进程创建pcb,将父进程pcb数据拷贝过来,这时候父子进程因为虚拟地址空间页表完全一样,因此他们的代码和数据看起来都是一样的。

       但是,进程应该具有独立性,修改任意进程数据不应该影响其他进程,所以子进程也应该开辟自己的物理内存来存储数据。

       但是,如果子进程不修改数据,再开辟空间,更新页表,就浪费了资源,所以,操作系统一开始并不开辟内存拷贝数据,而是等一个进程修改数据后再给子进程开辟新的物理内存,拷贝数据---写时拷贝技术

      再简单介绍一下vfork --- 父子进程共用一块虚拟地址空间 , 因为vfork在很多系统上有问题, 所以不建议使用。

      vfork子进程运行,父进程阻塞,直到子进程结束。

      2.进程终止

    进程退出的时候,会保存退出原因,从而知道进程任务是否正确完成。

    进程退出场景:

          1.正常退出,结果正确;

          2.正常退出,结果错误;

            3.异常退出,结果不能作为判断标准

      进程的退出方式:

          1.main中return;

          2.调用exit函数;  --- 1,2都是先刷新缓冲区,做了其他释放工作才推出

          3.调用_exit函数;   --- 粗暴退出,直接释放所有资源

    

    3.进程等待

      为什么要进程等待呢? 因为要避免僵尸进程

      因为父进程不知道子进程什么时候退出,所以创建子进程后要一直等待子进程退出

      函数介绍:

        

         阻塞: 为了完成操作发起调用,如果当前不具备完成条件,则一直等待,直到完成操作。

         阻塞和非阻塞的区别: 发起调用后是否立即返回。 

        获取子进程status: 

          wait和waitpid都有一个输出型参数status,由操作系统填充。

          status不能简单当做整型来看,而是一个位图,具体细节如下:

                       

            测试验证代码:

            coredump标志 : 核心转储标志

            在程序异常退出时,保存程序的堆栈信息,方便事后调试  (核心转储通常默认是关闭的: 安全隐患 和 空间占用)

  

    4.程序替换

    前面我们知道,一个进程运行什么代码,取决于虚拟地址空间中的代码段映射物理地址中的那个真实代码区域。

      意味着如果将虚拟地址代码段映射到物理内存的代码位置替换成另一个程序的位置,那么进程将运行另一个程序。

      

      是什么 : 替换代码映射的代码位置成为另一个内存区域代码的位置,并且重新初始化数据段

       为什么 : 大多数情况下,我们创建一个子进程都是为了让子进程运行另一个程序,做其他的任务

       实现 : 操作系统提供了一套接口都能实现程序替换,统称为exec函数族     

#include<unistd.h>

int execl(const char* path,const char* arg,...);  //后面以NULL结束
int execlp(const char* file,const char* arg,...);
int execle(const char* path,const char* grg,...,char* const envp[]); int execv(const char* path,const char* argv); //argv数组也要以NULL结束
int execvp(const char* file,const char* argv);
int execve(const char* path,const char* argv,char* const envp[]); //envp数组也是NULL结束 //事实上,只有execve是系统调用,其它函数都调用了execve

      2.函数参数

      path:表示对应的文件在哪个目录下(也表示我要执行的程序是哪一个);

      file:只用填文件名,系统会在PATH下找;

      envp[]:表示自己设置的,替换后的程序的环境变量

      3.命令理解

      l(list):表示参数采用列表形式

      v(vector):参数采用数组形式

      p(path):有p自动搜索环境变量PATH

      e(envp):表示自己设置(维护)环境变量(自己设置的环境变量是什么,则最新程序的环境变量就是什么)

      理论讲了这么多,不如写个测试代码,看看怎么用吧:

#include <unistd.h>
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};

execl("/bin/ps", "ps", "-ef", NULL);

// 带p的,可以使用环境变量PATH,无需写全路径
execlp("ps", "ps", "-ef", NULL);

// 带e的,需要自己组装环境变量
execle("ps", "ps", "-ef", NULL, envp);

execv("/bin/ps", argv);
// 带p的,可以使用环境变量PATH,无需写全路径
execvp("ps", argv);

// 带e的,需要自己组装环境变量
execve("/bin/ps", argv, envp);
exit(0);
}

  

Linux 进程控制的更多相关文章

  1. Linux进程控制(二)

    1. 进程的创建 Linux下有四类创建子进程的函数:system(),fork(),exec*(),popen() 1.1. system函数 原型: #include <stdlib.h&g ...

  2. Linux进程控制(一)

    1. Linux进程概述 进程是一个程序一次执行的过程,它和程序有本质区别.程序是静态的,它是一些保存在磁盘上的指令的有序集合:而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建.调度 ...

  3. Linux - 进程控制 代码(C)

    进程控制 代码(C) 本文地址:http://blog.csdn.net/caroline_wendy 输出进程ID.getpid(). 代码: /*By C.L.Wang * Eclipse CDT ...

  4. Linux进程控制(三)

    1. 进程间打开文件的继承 1.1. 用fork继承打开的文件 fork以后的子进程自动继承了父进程的打开的文件,继承以后,父进程关闭打开的文件不会对子进程造成影响. 示例: #include < ...

  5. Linux进程控制——exec函数族

    原文:http://www.cnblogs.com/hnrainll/archive/2011/07/23/2114854.html 1.简介 在Linux中,并不存在exec()函数,exec指的是 ...

  6. LINUX进程控制

    1. 引言 一个程序是存储在文件中的机器指令序列.一般它是由编译器将源代码编译成二进制格式的代码.运行一个程序意味着将这个机器指令序列载入内存然后让处理器(cpu)逐条执行这些指令. 在Unix术语中 ...

  7. linux进程控制命令

    & 加在一个命令的最后,可以把这个命令放到后台执行 ,如gftp &. ctrl + z 可以将一个正在前台执行的命令放到后台,并且处于暂停状态,不可执行. jobs 查看当前有多少在 ...

  8. linux 进程控制笔记

    进程创建 普通函数调用完成后,最多返回(return)一次,但fork/vfork会返回二次,一次返回给父进程,一次返回给子进程 父进程的返回值为子进程的进程ID,子进程的返回值为0 1.pid_t ...

  9. linux进程控制开发实例

    fork.c #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include < ...

随机推荐

  1. Mybatis笔记(二)

    目录 MyBatis 逆向工程 MyBatis Generator 使用 分页插件 1.下载分页插件 2.配置分页插件 3.使用分页插件 SSM整合(spring与springMVC) 1.创建web ...

  2. Perl深度优先迷宫算法

    迷宫求解,可以用穷举法,将每个点的方向都穷举完:由于在求解过程中会遇到某一方向不可通过,此时就必须按原路返回. 想到用Perl数组来保存路径,记录每次所探索的方向,方便原路返回时得到上一步的方向,再退 ...

  3. ubuntu进程监视器htop 清除黄色内存(缓存)

    大意是:对于CPU显示条: 蓝色为:低优先级的线程 绿色为:正常优先级线程 红色为:内核线程 对于内存显示条: 蓝色为:缓冲区(buffers) 绿色为:已使用的内存 (橘)黄色为:高速缓存(cach ...

  4. if ( ! defined('BASEPATH')) exit('No direct script access allowed')的作用

    在看源代码时,发现codeigniter框架的控制器中,总是加上这样一段话: if(!defined('BASEPATH'))exit('No direct script access allowed ...

  5. JVM 自定义类加载器在复杂类情况下的运行分析

    一.自定义类加载器在复杂类情况下的运行分析 1.使用之前创建的类加载器 public class MyTest16 extends ClassLoader{ private String classN ...

  6. Spring Boot核心原理

    Spring Boot核心原理 spring-boot-starter-xxx  方便开发和配置 1.没有depoy setup tomcat 2.xml文件里面的没有没有了 @SpringBootA ...

  7. Qt动画框架The Animation Framework

    动画框架是Kinetic(运动)项目的一部分,它的目标是提供一中简单的方法创建动画的和流畅的GUI.借助Qt动画属性,可以提供非常自由的动画窗体组件和其他对象(QObjects).动画框架也能被用于图 ...

  8. nginx 80 下的一个路径 到 8888

    # For more information on configuration, see:# * Official English Documentation: http://nginx.org/en ...

  9. android -------- java.net.UnknownServiceException

    最近升级了Android的API版本时 ,导致我的网络请求失败了, 出现了这个错误 java.net.UnknownServiceException, 这个错误,我在网上查到这个主要是由于,我们的Ok ...

  10. 产品经理 写SQL

    产品经理必备技能:写SQL - 云+社区 - 腾讯云https://cloud.tencent.com/developer/news/3177 产品经理学SQL(一)一个小时上手SQL | 人人都是产 ...