父子进程的关系:
子进程是父进程的副本。子进程获得父进程数据段,堆,栈,正文段共享。(子分配了一块新的内存,但是代码段指向父进程,也就是说不论几个子进程都只有一个code段)
     
     在fork之后,一般情况那个会先运行,是不确定的。如果非要确定那个要先运行,需要IPC机制。
     
     区别:
     1)fork的返回值
     2)pid不同
进程的终止:8种情况
    1)main 中return
     2)exit(), c库函数,会执行io库的清理工作,关闭所有的流,以及所有打开的文件,调用清理函数(atexit)。
     (int atexit(void (* function) (void)))(回调函数,用于调用程序员自己写的清理函数) 
     3)_exit,_Exit 会关闭所有的已经打开的文件,不执行清理函数。
     4)  主线程退出
     5)主线程调用pthread_exit(使单个线程退出)
     6)abort()(强行终止线程,作为异常终止)
     7)signal   kill pid(外部信号,例如kill)
     8)最后一个线程被pthread_cancle(系统的线程取消请求,但其实不等于线程结束)
exit 库函数
    退出状态,终止的进程会通知父进程,自己使如何终止的。如果是正常结束(终止),则由exit传入的参数。如果是异常终止,则有内核通知异常终止原因的状态。任何情况下,负进程都能使用wait,waitpid获得这个状态,以及资源的回收。
     void exit(int status) 
     exit(1);
     功能:
         让进程退出,并刷新缓存区
     参数:
         status:进程退出的状态
     返回值:
         缺省
     
     EXIT_SUCCESS    0
     EXIT_FAILURE    非0(1~128,c语言错误列表共有128个)
    return  当该关键字出现在main函数中时候可以结束进程
             如果在其他函数中则表示结束该函数。
     exit -> 刷新缓存区 -> atexit注册的退出函数 -> _exit
atexit(回调函数)
int atexit(void (*function)(void));
     功能:
         注册进程退出前执行的函数(也就是参数function,需要程序员自己构建)
     参数:
         function:函数指针
             指向void返回值void参数的函数指针
     返回值:
         成功返回0
         失败返回非0
    当程序调用exit或者由main函数执行return时,所有用atexit
     注册的退出函数,将会由注册时顺序倒序被调用
wait:
    pid_t wait(int *status);
 功能:该函数可以阻塞等待任意子进程退出
       并回收该进程的状态。
       一般用于父进程回收子进程状态。
参数:status 进程退出时候的状态
       如果不关心其退出状态一般用NULL表示
       如果要回收进程退出状态,则用WEXITSTATUS回收。
返回值:成功 回收的子进程pid
         失败 -1;
退出状态:
WIFEXITED(status) 是不是正常结束
WEXITSTATUS(status) 使用这个宏去接收返回值(exit函数的返回值)
WIFSIGNALED(status) 是不是收到了信号而终止的
WTERMSIG(status)如果是信号终止的,那么是几号信号。
(比如使用终端的kill命令,kill -9 pid号,此时的这个宏得到的值应该是9)
以上退出状态两个两个一组使用:
        int status;pid_t recycle_pid = wait(&status);if(WIFEXITED(status)){  printf("child normal terminal,recycle pid %d , exit value %d\n",recycle_pid,WEXITSTATUS(status));}if(WIFSIGNALED(status)){printf("child terminal by signal ,rrecycle pid %d, signal num %d \n",recycle_pid,WTERMSIG(status));}注:
    1)如果所有的子进程都在运行,在阻塞
     2)如果一个子进程终止,正在等待的父进程则获得终止状态,获得子进程的状态后,立刻返回。
     3)如果没有子进程,则立即出错退出。
  
waitpid:
pid_t waitpid(pid_t pid, int *status, int options);(功能更强大的wait)
     < -1 回收指定进程组内的任意子进程
     -1 回收任意子进程,组内外
     0 回收和当前调用waitpid一个组的所有子进程,组内
     > 0 回收指定ID的子进程
      waitpid (-1,a,0)  == wait(a);(阻塞等待回收组内外任意子进程)
      status 子进程退出时候的状态,//一般使用非阻塞,因为如果阻塞的话,无法及时接收到数据
                                                        如果不关注退出状态用NULL;
       options 选项:(是否阻塞)
                   0  表示回收过程会阻塞等待  
                 WNOHANG 表示非阻塞模式回收资源。
     返回值:成功 返回接收资源的子进程pid
         失败  -1
         0,