当前位置: 首页 > news >正文

Linux——进程(2)

一、父子进程的关系

  •     子进程是父进程的副本。
  •     子进程获得父进程数据段,堆,栈,正文段共享。
  •     在fork之后,一般情况哪个会先运行,是不确定的。
  •     如果非要确定那个要先运行,需要IPC机制。

    1、区别


    1)fork的返回值
    2)pid不同


二、创建进程(fork())


  注意:
           1.创建之后,父子进程各自拥有4g独立的内存空间 
           2.各自拥有自己的相关的程序的各个段 数据段,所以,各自之间对数据的改变,不会相互                  影响 
           3.子进程会继承父进程已打开的文件描述符 
             若,fork之前打开文件,父子进程操作同一个文件,相互间有影响
             若,fork之后打开文件,父子进程操作同一个文件,但是,因为各自拥有自己的 "文件表                 项",所以,各自按照自己的逻辑改变文件。


三、进程的终止(8种情况)


    1)main 中 return
    2)exit() //库函数 
       c库函数,会执行io库的清理工作,关闭所有 的流,以及所有打开的文件。注册清理函数               (atexit)。
    3)_exit,_Exit 会关闭所有的已经打开的文件,不执行清理函数。 //系统调用 
    4) 主线程退出  
    5)主线程调用pthread_exit 
    
    异常终止:
    6)abort()
    7)signal   kill pid
    8) 最后一个线程被pthread_cancle

     
四、进程的退出

1、僵尸进程和孤儿进程    


    孤儿进程:
      特点:
           子进程还在,但父进程已经结束了。此时,避免子进程将来没有人收尸,
           由init进程来收养子进程。
    
    僵尸进程:
      特点:
          父进程还在,子进程先结束了。父进程没有做收尸操作。
          此时,子进程进入僵尸态。(wait/waitpid --- 查看子进程的退出状态)

五、僵尸进程


            进程执行结束但空间未被回收变成僵尸进程

    1.exit(库函数)


            退出状态,终止的进程会通知父进程,自己使如何终止的。    
            如果是正常结束(终止),则由exit传入的参数。
            如果是异常终止,则有内核通知异常终止原因的状态。
            任何情况下,父进程都能使用wait,waitpid获得这个状态,以及资源的回收。
    void exit(int status) 
    exit(1);
    功能:
        让进程退出,并刷新缓存区
    参数:
        status:进程退出的状态
    返回值:
        缺省

    return  当该关键字出现在main函数中时候可以结束进程
            如果在其他函数中则表示结束该函数。


2._exit(系统调用)


    void _exit(int status);
    功能:
        让进程退出,不刷新缓存区
    参数:
        status:进程退出状态
    返回值:
        缺省


3.atexit


    int atexit(void (*function)(void));
    功能:
        注册进程退出前执行的函数
    参数:
        function:函数指针
            指向void返回值void参数的函数指针
    返回值:
        成功返回0
        失败返回非0

    当程序调用exit或者由main函数执行return时,所有用atexit
    注册的退出函数,将会由注册时顺序倒序被调用

注意:
   a. 是exit函数调用时,会调atexit函数 
      _exit函数调用时,不会调到atexit
   b. atexit 程序正常结束
      (1).main 返回 //exit 
      (2).exit()        
   c.atexit函数 可以多次注册 
   d.最后"退出清理函数"的调用顺序,与注册顺序相反。

六.进程空间的回收


1、void exit(int status);


    wait/waitpid
    exit(EXIT_SUCCESS);// EXIT_SUCCESS ---退出状态值 
    pid_t wait(int *status);//wait 来获取到 
功能:该函数可以阻塞等待任意子进程退出
           并回收该进程的状态。
           一般用于父进程回收子进程状态。

参数:status 进程退出时候的状态
           如果不关心其退出状态一般用NULL表示
          如果要回收进程退出状态,则用WEXITSTATUS回收。

返回值:成功 回收的子进程pid
              失败 -1;
WIFEXITED(status)   是不是正常结束
WEXITSTATUS(status) 使用这个宏去那返回值
WIFSIGNALED(status) 是不是收到了信号而终止的
WTERMSIG(status)    如果是信号终止的,那么是几号信号。

2、pid_t wait(int *status);

    1)如果所有的子进程都在运行,在阻塞
    2)如果一个子进程终止,正在等待的父进程则获得终止状态,获得子进程的状态后,立刻返                回。
    3)如果没有子进程,则立即出错退出。

    waitpid(-1,status,0)=wait(status);
    pid_t waitpid(pid_t pid, int *status, int options);
    
    <-1 回收指定进程组内的任意子进程
     -1 回收任意子进程,组内外
      0 回收和当前调用waitpid一个组的所有子进程,组内
     >0 回收指定ID的子进程
     
     @pid 的值 
       
       < -1   meaning wait for any child process whose  process  group  ID  is
              equal to the absolute value of pid.

       -1     meaning wait for any child process.

       0      meaning  wait  for  any  child process whose process group ID is
              equal to that of the calling process.

       > 0    meaning wait for the child whose process  ID  is  equal  to  the
              value of pid.


3、waitpid (-1,a,0)  == wait(a);


     参数:
     status 子进程退出时候的状态,
              如果不关注退出状态用NULL;
     options 选项:
                  0       表示回收过程会阻塞等待
                WNOHANG 表示非阻塞模式回收资源。
                
    返回值:成功 返回接收资源的子进程pid
                   失败  -1
        wait(); 
        waitpid(-1,&status,0); <=> wait
        waitpid(pid,&status,0); //默认的当时,默认就是阻塞方式 
        waitpid(pid,&status,WNOHANG);// 非阻塞的方式 
        wait(&status) <=> waitpid(-1,&status,0); //阻塞 形式
        waitpid(-1,&status,WNOHANG);//非阻塞形式     


4、wait 和waitpid的比较


功能:
    都是来等待子进程状态改变的 
wait    ---阻塞的版本,子进程的结束状态 
waitpid --- 可以实现一个非阻塞版本的等待,其实还可以检测子进程的其他的状态改变。
注意: 
   waitpid 实现一个非阻塞版本的 回收操作,但是,要想能够实现收尸操作,必须,要使用轮询(while)
收尸操作:
   1.wait 
   2.waitpid 
   3.孤儿进程 
     fork 
       |
     父进程 exit()


七、exec族


        用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),
子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的
用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建
新进程,所以调用exec前后该进程的id并未改变。

1、exec函数


        其实有六种以exec开头的函数,统称exec函数:
vector
ls -l -i list 
execl("/bin/ls","-l","-i",NULL);
execlp("ls","-l","-i",NULL);

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);

key=value
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);

int execve(const char*path,char*const argv[],char*const evnp[]);
int execlp(const char *file, const char *arg, ...);

2、这些函数的区别


    1),前4个使用路径名作为参数,后面两个使用文件名做参数
    当filename中,含有/时视为路径名,否则就按PATH变量,在指定目录下查找可执行文件。
    2)相关的参数表传递
    l表示list,v表示vector
    execl,execlp,execle,需要将参数一个一个列出,并以NULL结尾。
    execv,execvp,execve,需要构造一个参数指针数组,然后将数组的地址传入。

    3)以e结尾的函数,可以传入一个指向环境字符串的指针数组的指针。其他未指定环境变量,使用父进程继承过来的。
        execve 是真正的系统调用
        这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。


注意:
路径加文件名
1.excle 
  带l的默认会搜索,当前路径下。
2.带p的只搜索 PATH系统环境变量


(1).带l  vs 带 v 


    int execl  (const char *path, const char *arg, ...); //list 
    int execv  (const char *path, char *const argv[]);//vector 
功能:
    执行一个文件 (可执行文件 a.out / 1.sh )
参数:
  @path   要执行的文件的路径(包含可执行文件的名字)
  @arg   表示 可执行文件的文件名 
 execl("/bin/ls","ls","-l","/",NULL);

区别:
    在于,参数传递的方式不同,
    l --- list ---参数逐个列举 
    v ---vector --- 参数组织成 指针数组的形式 


(2). p和e的区别

        带p 表示可执行文件的寻找方式,是从系统的环境变量PATH中的路径下面去找
        带e 表示的是可以给要执行的 新程序 传递需要的 环境变量 

        extern char **environ; //系统的环境变量信息 的指针数组的首地址 

真正的系统调用:
execve  

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • IO多路复用—前言
  • 【OneAPI】中国行政区域省市县编码查询
  • 集成学习:融合多个模型
  • 负载均衡之HAProxy超全内容!!!
  • SDL 与 OpenGL 的关系
  • Vue3学习 Day01
  • 张量补充 2 (补充ing)
  • WPF使用LibVLC.WPF进行本地视频文件播放
  • 【CTF | WEB】003、攻防世界WEB题目之xff_referer
  • 设计模式-享元模式
  • HTTP 之 头部信息(二)
  • Vue3+vite+ts 项目使用mockjs
  • 【C++ 面试 - 基础题】每日 3 题(十六)
  • 质量对中国开发商提升游戏品牌信誉和信任度的影响
  • Java设计模式之中介者模式
  • @angular/forms 源码解析之双向绑定
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • Java 23种设计模式 之单例模式 7种实现方式
  • Javascript弹出层-初探
  • Redash本地开发环境搭建
  • Redis 中的布隆过滤器
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • sessionStorage和localStorage
  • SpringBoot几种定时任务的实现方式
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • vue 个人积累(使用工具,组件)
  • vue数据传递--我有特殊的实现技巧
  • webpack4 一点通
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 力扣(LeetCode)56
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 思否第一天
  • 突破自己的技术思维
  • 我这样减少了26.5M Java内存!
  • 自制字幕遮挡器
  • 阿里云ACE认证学习知识点梳理
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​十个常见的 Python 脚本 (详细介绍 + 代码举例)
  • # Java NIO(一)FileChannel
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • (arch)linux 转换文件编码格式
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (Java入门)抽象类,接口,内部类
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (PADS学习)第二章:原理图绘制 第一部分
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (二)linux使用docker容器运行mysql
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (小白学Java)Java简介和基本配置
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (状压dp)uva 10817 Headmaster's Headache
  • *p++,*(p++),*++p,(*p)++区别?