Linux系统基础(进程相关操作)

一、基本概念

  1. 进程与程序
    程序:存储在磁盘上的文件,包含可执行指令和数据的静态实体
    进程:运行中的程序(一个程序可以执行多次,加载出多个进程)
    进程就是处于活动状态的计算机程序
  2. 进程的分类
    交互进程:有输入有输出。用户可以根据自己的情况输入数据,得到想要的结果(一般进程)
    批处理进程:由脚本加载执行的程序(Linux下的shell,windows下的bat)
    守护进程:总是活跃的、后台运行,一般由系统开机时加载执行,或root用户手动加载执行
  3. 察看进程:
    简单方式:ps,显示当前用户有终端控制权的进程信息
    列表形式:aux,一列表形式显示详细信息
    a所有用户的终端控制进程
    u详细方式显示
    x所有无终端控制的进程
  4. 进程的详细信息列表
    USER:进程的用户名
    PID:进程ID
    %CPU 进程的CPU使用率
    %MEM 内存的使用率
    VSZ 虚拟内存占用的字节数
    RSS 占用物理内存的大小
    TTY 终端的次设备号,如果无终端控制权显示?
    STAT 进程的状态
    O 就绪态,等待被系统调用
    R 运行态,Linux系统下没有就绪态,也用R表示
    S 休眠态,可以被系统中断,也就是被中断信号唤醒进入运行态
    T 暂停态,是被SIFSTOP信号暂停的,当收到SIGCONT信号才能再转入运行
    Z 僵尸态,已经结束停止运行,但父进程还没有回收
    < 表示高优先级进程
    N 表示低优先级
    l 多线程
    + 在前台进程组中的进程
    s 会话首进程
    START TIME 进程的开始时间
    COMMAND 进程的程序名
  5. 父进程与子进程 孤儿进程与僵尸进程
    一个进程A可以创建另一个进程B 创建者叫父进程,被创建者叫子进程,
    父进程启动子进程,在操作系统的调用下父进程同时执行(同步)
    如果子进程先于父进程结束,会向父进程发送SIGCHID信号,父进程收到信号后就应该去回收子进程的相关资源
    但在默认情况下,父进程忽略该信号。当子进程结束后,父进程没有回收子进程的资源,子进程就变成了僵尸进程
    如果父进程先于子进程结束,子进程就变成了孤儿进程,同时被孤儿院收养(init),然后就变成了init的子进程

二、进程标识符

操作系统会为每个进程分配唯一的标志符,采用无符号整数表示,即进程ID
进程ID在任何时候都是唯一的,但是可以重用,当一进程结束,新创建的进程才可以使用它的进程ID(延时重用)
pid_t getpid(void);
功能:获取进程ID
pid_t getppid(void);
功能:获取父进程ID
uid_t getuid(void);
功能:获取当前进程的用户ID
gid_t getgid(void);
功能:获取当前的组ID
getpgid
获取pid进程组的进程组ID
setpgid
设定

三、fork

pid_t fork(void)
功能:创建一个新进程
返回值:一次调用,两次返回 失败返回-1(当进程数超出系统的限制的时候)

  1. 两次返回分别是子进程ID和0,父进程会拿到子进程ID,子进程返回0,借此可以分别出父子进程
  2. 通过fork创建子进程就是父进程的副本(拷贝)
    子进程会获取父进程的数据段、bss段、堆、栈、IO流(共享文件指针和文件描述符、缓冲区的拷贝
    ,与父进程共享代码段
  3. 子进程会继承父进程的信号处理方式
  4. fork函数调用后,父子进程各自执行,谁先返回不一定。但可以使用一些特殊手法来确保谁先执行
  5. 僵尸进程和孤儿进程的实现
  6. 子进程和父进程是并发执行的,一般用于多任务
    练习一:实现一个程序来验证,子进程确实拷贝了父进程的数据段、bss段、堆、栈、IO流 共享文件指针和文件描述符

四、进程的正常退出

  1. 从main函数中return。
  2. 调用标准库中的exit函数(在任意位置,exit(0)相当于main中的return) 后面的数值会被操作系统拿到
    void exit(int status);
    调用者立即结束该进程
    status:退出状态码,可以在父进程中获取到,子进程留给父进程的遗言
    退出前做的事情:
    1)先调用事先注册的函数(atexit/on_exit)
    int atexit(void (*function)(void));
    功能:注册一个函数,当进程通过exit函数结束时调用
    function:函数指针,无返回值,无参数
    int on_exit(void (*function)(int , void *), void *arg);
    功能:注册一个函数,当进程通过exit函数开始结束时调用
    function:函数指针,无返回值,参数1为exit函数的参数,参数2为on_exit函数的第二个参数
    arg:当function函数被调用时传递给他的第二个参数
    2)fflush冲刷所有处理未关闭状态的标准IO流,删除所有临时文件
    3)返回整数给操作系统(EXIT_SUCCESS/EXIT_FAILURE)
    4)该函数不会返回,它的功能实现借助了 _exit/ _Exit

注意:两个函数的功能是一样的
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);//调用系统的_exit为了兼容性
功能:调用的进程会结束,没有返回值
status:这个参数会被父进程获取到(低八位,一个字节)
1)进程结束前会关闭所有处于打开状态的文件描述符
2)把所有的子进程托付给init(孤儿院)
3)向它的父进程发送SIGCHLD信号
注意:exit函数也会执行以上操作,因此它底层调用了 _exit / _Exit
4)进程的最后一个线程执行了最后一条语句。
5)进程的最后一个线程掉用了pthread_exit函数

五、进程的异常退出

  1. 调用了abort函数,该函数产生一个 SIGABRT 信号
  2. 进程接受到一些信号,无捕获处理,或无法捕获处理
  3. 进程的最后一个线程接受到取消请求,并对请求做出响应(类似于线程收到结束信号)

六、wait/waitpid

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
功能:等待所有子进程结束,并获取到最后的状态码,只要有一个进程结束就立即返回

  1. 应该是父进程接受到子进程发送来的SIGCHLD信号时,调用wait函数回收子进程的资源并获取结束状态
  2. 如果所有子进程都在运行,则wait阻塞,
  3. 如果有僵尸进程,wait也会立即返回,回收资源获取结束状态码
  4. 如果没有子进程则返回失败-1
    pid_t waitpid(pid_t pid, int *status, int options);
    功能:等待指定的进程结束,并获取到最终的状态码
    WNOHANG:非阻塞模式 如果没有子进程则立即退出
    WUNTRACED:如果子进程属于暂停状态,则返回他的状态
    WCONTINUED:如果子进程从暂停转为继续,则返回他的状态
    0:阻塞状态

pid的值
=-1 等待任意子进程结束,此时与wait等价
>0 等待进程号为pid的进程结束,此时只等待一个进程结束
=0 等待同组的任一子进程结束,此时等待的是整个进程组
<-1 等待的是进程组ID是pid绝对值中的任一子进程结束,

  1. wait函数只能孤独的等待子进程结束,而waitpid可以有更多的选择
  2. waitpid不仅仅可以等待子进程,也可以等待同组进程,
  3. 可以阻塞也可以不阻塞
  4. 可以监控子进程的暂停或继续状况

七、vfork

pid_t vfork(void);
功能:与fork功能基本一致
区别:通过vfork创建的进程不复制父进程的地址(空间数据段、bss段、堆、栈、IO流、共享文件指针和文件描述符、缓冲区的拷贝)
必须通过excl系列函数加载自己的可执行程序。
注意:当执行vfork时,先返回的是子进程,此时他占用父进程的地址空间,当子进程成功创建后(通过excl加载可执行程序),父进程才返回

八、execl

功能:加载子进程的可执行文件。
int execl(const char *path, const char *arg, …);
path:可执行文件的路径
arg:第一个main函数的参数,最后一个必须是NULL结尾
int execlp(const char *file, const char *arg, …);
file:可执行文件的名字,可以从环境变量表中查询
arg:第一个main函数的参数,最后一个必须是NULL结尾
int execle(const char *path, const char *arg,
…, char * const envp[]);
envp:父进程的环境变量表传递给子进程
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]);

九、system

int system(const char *command);
功能:执行系统命令,也可以加载可执行程序。
相当于创建了一个子进程,但子进程不结束,该函数不返回,父子进程不会同时执行
该函数的实现调用了:vfork、exec、wait

十、进程组

进程组:是由一个或多个进程的集合,每一个进程除了一个进程ID还有一个组ID,
进程组中的进程归属同一个作业控制
同意进程组的进程,会统一接收到终端的信号,由相当于加入gpid
每一个进程都有一个进程组组长,组长的进程ID就是组ID
pid_t getpgid(pid_t pid);
功能:获取pid进程的进程组ID
int setpgid(pid_t pid, pid_t pgid);
设置pid进程的进程组ID,相当于加入了pgid进程组,pgid就是组长

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值