前言:前面我们了解了进程的创建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号的子进程中的任意一个进程!
指定等待进程号为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
 从小到大连续分配!
 进程结束,进程号释放,但是释放的进程号不会重新分配!
 只要系统没有重启,进程号就不会二次分配!