Linux学习系列(九):Linux进程复制和替换

目录

  • 一.main函数
  • 二.printf输出问题
    • 1.printf 函数并不会直接将数据输出到屏幕,而是**先放到缓冲区**中,只有一下三种情况满足,才会输出到屏幕。
    • 2.退出:return exit _exit
  • 三.fork进程复制,写时拷贝
    • 1.fork
    • 2.写时拷贝
  • 四.僵死进程、孤儿进程及处理方法
    • 1.僵死进程
    • 2.孤儿进程
    • 3.僵死进程处理方法
  • 五.操作系统的文件调用
    • 1.open
    • 2.close
    • 3.read
    • 4.write
    • 5.先open再fork
    • 6.先fork再open
  • 六.进程替换

一.main函数

int main( int argc, char* argv[], char* envp[])

  • (1) argc 参数个数

  • (2) argv 字符数组 存放 参数内容

  • (3) envp 字符数组 存放 环境变量(从父进程继承下来的)

Linux学习系列(九):Linux进程复制和替换_第1张图片
Linux学习系列(九):Linux进程复制和替换_第2张图片

二.printf输出问题

1.printf 函数并不会直接将数据输出到屏幕,而是先放到缓冲区中,只有一下三种情况满足,才会输出到屏幕。

  • 1) 缓冲区满

  • 2) 强制刷新缓冲区 fflush 用法:fflush(stdout);

  • 3) 程序结束时

  • 4)碰见\n

fflush+_exit==exit(0)
Linux学习系列(九):Linux进程复制和替换_第3张图片
在这里插入图片描述
在这里插入图片描述
printf并没有第一时间输出,而是等程序结束时才显示。而碰到其他情况就刷新缓冲区,直接输出到屏幕上

2.退出:return exit _exit

return:关键字,当前功能结束

exit:函数调用,进程退出 结束进程前,刷新缓冲区,再调用_exit

_exit:内核级别函数,不刷新缓冲区,只结束程序

三.fork进程复制,写时拷贝

1.fork

  • fork():返回类型pid_t(int重命名),无参数,所在头文件unistd.h。 先拷贝PCB,再拷贝进程实体

  • 若返回值>0 则为父进程,父进程继续跑,产生子进程 同一个进程同一个pid

    返回值==0 则为子进程,完全复制当前进程信息(目前已知只有pid不同)为子进程,从下一行语句开始执行

  • getpid()获取当前进程的pid

    getppid()获取父进程的pid 对应的头文件与fork一样
    Linux学习系列(九):Linux进程复制和替换_第4张图片

    bash:命令解释器 也是一个进程 当前进程的父进程

    Linux学习系列(九):Linux进程复制和替换_第5张图片

2.写时拷贝

  • 写时拷贝:父进程和子进程是同一个逻辑地址,但不是同一个物理地址 一般子进程的pid号是父进程的pid+1
    父进程和子进程刚开始是公用同一个物理地址的,但当页内容发生改变时,才会将父进程的内容复制一份给子进程,改变的页表信息独立一个物理地址,页表其余没变的页表信息和父进程一样

四.僵死进程、孤儿进程及处理方法

1.僵死进程

  • 僵死进程:子进程先于父进程结束, |而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。
    PCB消失的条件是获取到退出码,子进程要父进程获取子进程的退出码
  • 危害占用资源空间。如果进程不调用wait/waitpid,那么保留的那段信息就不会被释放,其进程号就会一 直被占用,但是系统能使用的进程号是有限的,如果产生大量的僵尸进程,将因为没有可用的进程号而 导致系统不能产生新的进程
    Linux学习系列(九):Linux进程复制和替换_第6张图片

2.孤儿进程

  • 孤儿进程父进程先于子进程结束,由init进程接管子进程
    Linux学习系列(九):Linux进程复制和替换_第7张图片

3.僵死进程处理方法

  • wait即先阻塞父进程,直至子进程运行结束,父进程获取到子进程的退出码后,父进程才继续运行
  • wait(&val):返回值pid_t,调用函数后会将退出码通过指针赋值到val上。
    WIFEXITED(val):由于退出码为1字节,val为4字节,通过该函数可以将其转化为1字节,返回值为bool类型,判断进程是否正常结束。
    WEXITSTATUS(val):获取进程退出状态。
    Linux学习系列(九):Linux进程复制和替换_第8张图片

五.操作系统的文件调用

头文件:fcntl.h

1.open

int fd = open(“./a.txt”,O_RDWR|O_CREAT,0600);

  • 返回值 :int
  • 文件描述符 fd对应一个文件 一般>0 文件关闭符归还操作系统 打开失败 fd=-1
  • 参数列表 : 路径+文件名,打开方式, 给予的权限(若存在则不需要这一参数):4,2,1,一般习惯前面加个0
  • 打开方式
    O_RDONLY 只读打开
    O_RDWR 读写方式打开
    O_CREAT 文件不存在则创建
    O_APPEND 文件末尾追加
    O_TRUNC 清空文件,重新写入
    注:多个打开方式加 |

2.close

close(fd) 关闭文件

3.read

ssize_t read(int fd, void* buf, size_t count); 从fd所对应的文件中读,读到buf中

  • fd 对应打开的文件描述符

  • buf 存放数据的空间

  • count 计划一次从文件中读多少字节数据

  • 返回值:为实际读到的字节数

4.write

ssize_t write(int fd, const void* buf,size_t count); 用buf中的数据写入到fd所对应的文件里

  • fd 对应打开的文件描述符

  • buf 存放待写入的数据

  • count 计划一次向文件中写多少数据

5.先open再fork

PCB中有一个文件表(结构体指针类型的数组),文件结构体里有如下内容:计数器为全局变量

  • 先打开文件,再fork,文件描述符中的a.txt为指针,指向文件结构体,而fork后,文件描述符也指向相同的文件结构体。则先open再fork,再打印abcd的a.txt文件,结果为abcd
    Linux学习系列(九):Linux进程复制和替换_第9张图片

6.先fork再open

  • 先fork再open则文件描述符中的a.txt指向不同的文件结构体,再打印abcd的a.txt,结果为abab
    Linux学习系列(九):Linux进程复制和替换_第10张图片

六.进程替换

  • 进程替换把当前进程替换为其他进程执行。PCB没变,只是进程实体变了

  • 头文件:unistd.h 前5个为库函数 底层调用系统调用函数execve
    p -> PATH e -> 环境变量 l -> 把参数列举出来 v ->参数封装到数组
    参数:绝对路径,命令(-后面每个字符都会解释其含义,–后面当作单词去解释)
    返回值:无
    带意味着从PATH路径中找文件名,(char*)0相当于命令的结尾标志,而用 buff就不用了,带e的添加参数envp
    可通过echo $PATH查看PATH路径,通过export PATH=$PATH:路径 ,添加用户自定义路径
    Linux学习系列(九):Linux进程复制和替换_第11张图片

  • execl(“/user/bin/ps”,“ps”,“-f”,(char*)0);

  • execlp(“ps”,“ps”,“-f”,(char*)0);

  • execle(“/user/bin/ps”,“ps”,“-f”,(char*)0,envp);

  • execv(“/user/bin/ps”,buff);

  • execvp(“ps”,buff);

  • execve(“/user/bin/ps”,buff,envp);

你可能感兴趣的:(Linux,linux,学习,服务器)