一、孤儿进程和僵尸进程
1)孤儿进程
- 失去父进程的子进程就叫做孤儿进程,孤儿进程的产生是由于父进程不等待子进程退出,即父进程在子进程之前就结束了自己的“生命”。
- Linux系统避免存在过多的孤儿进程,init(pid=1)进程会”领养“孤儿进程,变成init的父进程。
init进程,它是内核启动的第一个用户级进程。init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程。
当内核启动了自己之后(已被装入内存、已经开始运行、已经初始化了所有的设备驱动程序和数据结构等等),通过启动用户级程序init来完成引导进程的内核部分。因此,init总是第一个进程(它的进程号总是1)。
2)僵尸进程
-
僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。
-
一个进程结束了,但是他的父进程没有等待(调用wait/waitpid)他, 那么他将变成一个僵尸进程
如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程, 因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程, 看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init 来接管他,成为他的父进程
3)如何区分孤儿进程和僵尸进程?
-
孤儿进程和僵尸进程都是指的子进程
-
由于父子进程被调度的顺序不同,进程先执行完,子进程叫孤儿进程;父进程后执行完,子进程叫僵尸进程(不一定)
4)如何避免产生僵尸进程?
父进程后执行完,子进程并不一定会变成僵尸进程,父进程执行完后只要调用wait/waitpid,释放子进程资源,子进程就不会变成僵尸进程。
二、进程或线程的退出方式
1)进程退出方式
杀死进程:kill(),int kill(pid_t pid, int sig);
正常退出:
- main函数中return
- exit(),
void exit(int status);
- _exit(),
void _exit(int status);
异常退出:
- 调用abort(),
void abort(void);
- 由信号终止
2)线程退出方式
杀死线程:pthread_cancel(),int pthread_cancel(pthread_t thread);
正常退出:pthread_exit(),void pthread_exit(void *retval);
三、命令查看(含main函数的进程或线程)
含main函数的进程或线程又叫主进程或主线程。
例如,查看temperature_pub进程是否已经退出ps -aux | grep temperature_pub
四、代码中判断(不含main函数的进程或线程)
1)判断进程是否退出
- 根据wait或waitpid函数的返回值就可以判断进程是否退出
//wait和waitpid都属于系统调用
/*1.获取子进程退出状态,并返回死掉的子进程ID
* 2.如果有多个子进程,则获取任意子进程并返回该子进程的进程ID
* 3.通过wstatus指针告诉父进程子进程是如何结束的
* 4.成功,返回子进程的进程号;失败,返回-1
*/
pid_t wait(int *wstatus);
/*1.pid参数指定回收某个子进程
* 2.通过wstatus指针告诉父进程子进程是如何结束的
* 3.options参数设置函数阻塞或非阻塞,WNOHANG函数非阻塞,设置为0,函数阻塞
* 4.返回值,>0:清理掉的子进程ID,-1:回收失败,无子进程,=0:参数3为WNOHANG,且子进程正在运行
*
pid_t waitpid(pid_t pid, int *wstatus, int options);
2)判断线程是否退出
- 设置pthread_kill函数的第二个参数为0,就可以根据函数返回值判断线程是否退出了
/*1.pthread_kill函数并不是kill线程,而是向指定线程发送一个signal
* 2.参数sig为0是一个保留信号,作用是判断线程是不是还活着
* 3.返回值:
成功:0
线程不存在:ESRCH
信号不合法:EINVAL
*/
int pthread_kill(pthread_t thread, int sig);