Linux探索------进程的终止,等待及特殊进程(七)

时间:2021-04-01 14:53:40

前言:前面我们了解了进程的创建fork()、进程号的获取,现在我们基序了解一下进程的相关操作:进程的终止、等待以及特殊进程。


1. 进程的终止

进程终止即结束一个进程!

进程终止的方法有以下几种:

        1)进程的标准终止方法exit(); 在当前进程中任何地方调用该函数,进程终止!
              结束进程时,会刷新缓存区! 缓存区中数据会正常起作用!
        2)return; 用来结束一个函数的!放在主函数中可以结束进程!
                结束进程时,会刷新缓存区!
        3)_exit(); 功能、用法和exit();相同!
                结束进程时,直接结束,不刷新缓存区!
        4)abort(); 结束一个进程! 在进程中任何地方调用都会结束当前进程!
               结束进程时,会刷新缓存区!
        5)给进程发信号! kill  -9  PID  
                直接发信号,杀死PID进程,不会刷新缓存区

 

exit(0);(这是最常用的一个方法,和入口main()相呼应)

函数原型:void  exit(int status);
函数功能:终止一个进程!该函数是进程的标准出口!
形参列表:status:返回给父进程当前进程的终止状态!
返回值:void

void  abort(void);
函数功能:结束一个进程!结束时刷新缓存区!
本质是一个信号!

  

2. 进程的等待

进程等待主要用途是:父进程等待子进程结束之后,回收释放子进程空间,然后才能结束!

进程的等待主要是为了防止孤儿进程产生!

进程等待函数:wait();  

主要用于父进程等待子进程!

 

wait();

头文件:#include <sys/types.h>
             #include <sys/wait.h>
函数原型:pid_t  wait(int *status);

函数功能:父进程调用该函数之后,会进入睡眠状态! 挂起等待!!!

                等到任意一个子进程结束,wait返回等到的子进程进程号。父进程结束!

形参列表:status:接收子进程返回的进程结束状态

返回值:

            成功:等待到的子进程进程号

            失败:-1

总结:
wait函数只能父进程等待子进程!
wait函数只能等待任意一个子进程结束返回!
wait函数可以和exit结合使用,接收子进程的结束状态!

       

 ps -aux  :  STAT

                        运行态:R/R+
                        就绪态:R/R+

                        等待态:S/S+  

waitpid();

函数原型:pid_t  waitpid(pid_t pid, int *status, int options);

函数功能:等待某一个进程结束,返回等待到的进程PID。

形参列表:

            pid:进程号

                    < -1 :等待 进程组ID等于pid绝对值的这些子进程中的任意一个

                    = -1 :等待任意一个子进程  ==  wait();

                    = 0 :等待 进程组ID等于当前调用进程PID号的子进程中的任意一个进程!

                    > 0 :指定等待进程号为PID的子进程

            status:接收等待到的子进程的返回值

            options:操作方式

                    0:默认操作方式

                    WNOHANG:非阻塞等待

返回值:

            成功:等待到的进程PID

            WNOHANG:没有子进程终止返回0

            失败:-1

进程组:默认情况下,同一组进程指的是,同一个父进程创建出来的子进程、子进程的子进程...

默认情况下,同一个进程组的这些进程的进程组ID就是父进程PID

 

3. 特殊的进程(了解)

3.1 孤儿进程: 父进程已经结束,子进程仍然在运行!

孤儿进程会交由1号进程托管,如果进程中有死循环,则会一直运行下去!

孤儿进程是对系统有危害,尽量避免出现,解决方法:父进程调用wait()函数!

守护进程:对系统的运行起到支持保护作用的进程!特点是系统启动守护进程运行,直到系统关机,守护进程终止!

3.2 僵尸进程:子进程结束,父进程还一直在运行! 子进程就变为僵尸进程!

僵尸进程尽量避免! 把工作量比较大的进程做为子进程!或者调用wait();

补充:
ctrl  +  z :把当前进程放入到后台执行

fg : 把后台程序重新放回终端执行


4. exec族函数

exec函数:进程替换!

system函数:进程调用!


system();

函数功能:在一个程序内部调用另一个可执行程序!

调用的时候,被调用可执行程序会在内存中开辟一个新的进程空间!

实现形式是函数形式!

 

 

exec函数族(了解就行)

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

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

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

  

int  execl(const char *path, const char *arg, ...);

函数功能:进程空间替换! 进程替换过程中进程号不变!!!

形参列表:

            path:带路径的可执行程序 <要替换为的可执行程序>

            const char *arg, ...:可变参  <可执行程序的传参列表>

返回值:失败:-1(只有失败才有返回值)


        例:execl(“/bin/ls”,  “声明”,  “-l”,  “-a”,  “--color=auto”,  NULL);

               功能等于:ls  -a  -l  --color=auto


 

int execv(const char *path, char *const argv[]);

函数功能:进程空间替换! 进程替换过程中进程号不变!!!
形参列表:
            path:带路径的可执行程序 <要替换为的可执行程序>
            argv:替换可执行程序的传参  <可执行程序的传参列表>
返回值: 失败:-1
例:char*  buf[] = {“声明”,  “-l”,  “-a”,  “--color=auto”,  NULL};
       等效于:execv(“/bin/ls”,  buf);



int execlp(const char *file, const char *arg, ...);
函数功能:进程空间替换! 进程替换过程中进程号不变!!!
形参列表:
            file:可执行程序(默认路径可自动识别)  <要替换为的可执行程序>
            const char *arg, ...:可变参  <可执行程序的传参列表>
返回值:失败:-1
        例:execl(“ls”,  “声明”,  “-l”,  “-a”,  “--color=auto”,  NULL);
               等效于:ls  -a  -l  --color=auto

 

5. 进程创建--vfork

fork();   vfork();

 

vfork();

函数原型: pid_t  vfork(void)

函数功能:创建子进程!

                父子进程共有父进程空间,子进程运行结束,父进程才能开始试运行!

                子进程结束必须加exit(),否则一直运行!

                当子进程调用exec主函数,子进程会分配自己的进程空间!

形参列表:无
返回值:
        成功:
                返回给父进程:子进程PID
                返回给子进程:0
        失败:-1

   

注意:

vfork一般都是和exec族函数结合使用! 
保证exec之前不会产生孤儿进程!
节省内存空间!

进程号:PID
从小到大连续分配!
进程结束,进程号释放,但是释放的进程号不会重新分配!
只要系统没有重启,进程号就不会二次分配!