目录
一、进程的创建
进程也可以创建进程 ,每个进程可以有多个子进程,比如shell窗口下敲的命令都是进程,它们的父进程都是shell脚本/bin/bash
通过下面的函数获取自身和父进程的PID
getpid() 返回自身PID
getppid() 返回父进程的PI
cpp
pid_t fork(void);
@return 创建成功返回两次值
一次值(子进程的PID)给到父进程中
另一次值(0)给到创建的子进程中
失败返回-1
-
父进程创建子进程后,可以通过判断fork的返回值来辨别是父进程/子进程,从而让它们执行不同的内容
-
两个进程会交替执行 (并发),子进程只执行fork之后的代码(这样也避免了自动地无限fork)
-
父、子进程有独立 的地址空间,互不影响,执行的顺序由操作系统决定
-
子进程虚拟内存的内容和父进程大部分相同,除了进程ID、父进程ID、fork返回值、进程运行时间、闹钟、未决信号集不同,同时遵循读时共享写时复制的原则节省开销
-
若父进程先结束 ,子进程在父进程结束的一刻成为孤儿进程 ,系统防止过多孤儿进程产生,会由init进程收养 ,然后子进程变成后台进程
-
若子进程先结束 ,父进程没有及时回收 (父进程暂停执行,阻塞等待子进程结束退出,然后获取子进程的退出状态),导致子进程变成僵尸进程
进程创建的实用场景:
一个父进程希望复制自己,使父、子进程同时执行不同代码段。这在网络编程中很常见------父进程等待客户端的服务请求,当收到请求后,父进程创建子进程来处理此请求,父进程则继续等待下一个请求,然后再创建新的子进程...( 这不就是梦寐以求的分身吗!!!)
所以可以把子进程看作是父进程希望能有人帮他做某个工作,既然帮他做这个工作,他当然有理由关心这个工作做没做完
对于子进程,他做完了工作可以看成正常退出,没做完工作则算异常退出
对于父进程,他创建完子进程也想收集子进程的退出状态,甚至可能什么都不做,就等着子进程执行完,然后获取它的退出状态,父进程才好去执行后面的任务
二、进程的退出
cpp
void exit(int status); //属于标准C库
void _exit(int status); //同下面一个属于系统调用
void _Exit(int status);
@param:进程的退出状态 通过status传递给父进程,如果是异常退出,则内核来产生退出状态传给父进程
这两类退出函数的区别即标准C库和系统调用的区别,标准C库函数大多有缓冲,结束进程时会刷新流(缓冲区)的内容
return和exit的区别:return用于退出当前函数,属于堆栈的返回
exit用于结束程序运行,0表示正常,1、-1表示异常,2表示找不到文件
进程退出的类型:
1.正常退出
- main函数中调用了return
- 进程调用了退出进程的函数
- 进程最后一个线程返回或调用pthread_exit
2.异常退出
- 进程调用abort函数
- 进程收到某些信号,如某个进程while1死循环时,占据CPU大量资源,ctrl C 可以强制退出进程
- 最后一个线程对取消请求作出响应
三、进程的回收
pid_t wait(int *status)
功能:阻塞等待任一子进程退出 ,并获取它的退出状态(不过,退出状态不是简单地由返回值得到,甚至与返回值无关)
@param: status--整型数指针,指向用来存放子进程退出状态的变量
为空时(NULL),说明父进程不关心子进程的退出状态,这种情况比较特殊,父进程不收集子进程的退出状态,子进程退出后也不会变成僵尸进程
非空时,子进程的退出状态放在了它指向的地址,但这个地址并没直接获得退出状态,还需要进一步判断,因为退出分为正常和异常
1)调用函数来判断是哪种退出,函数名被定义成了几个宏,常用的是WIFEXITED、WIFSIGNALED,前者用来判断是否正常退出,后者判断是否异常退出,如果函数的返回值为真,则代表是对应判断的退出,如 if (WIFEXITED(state) == 1)
2)调用函数来获得退出状态,正常退出、异常退出分别用WEXITSTATUS、WTERMSIG来返回对应的退出状态信息,如WEITSTATUS(state)
@return:成功则返回退出的子进程PID,失败返回-1
pid_t waitpid((pid_t pid, int *status, int options);功能:多用于不傻等子进程退出(当然,不及时回收容易导致子进程退出后变为僵尸进程)
@param: pid
‐1 等待任一子进程 与wait等价
> 0 等待指定进程
0 等待当前进程组的任一子进程
< -1 等待指定进程组中的任一子进程,进程组ID等于pid的绝对值
status 同wait函数
options
0 阻塞等待
WNOHANG 不阻塞等待(迅速返回结果表示子进程执行阶段)可以循环不断去检测返回值
返回值 == 0表示子进程还在执行,父进程可以继续做自己的事,
返回值 > 0表示子进程执行结束,返回值变为子进程PID,后续可以通过调用WEXITSTATUS回收它
@return: 子进程退出返回PID,没执行完会返回0