经典C语言面试题6:进程与线程的关系和区别

一、定义

进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

线程:是进程的一个实体,是cpu调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源,但是它可以和同属于一个进程的其他线程共享进程所拥有的的全部资源。

二、关系和区别

一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。相对于进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他进程共享数据,但是拥有自己的栈空间,拥有独立的运行序列。

区别主要有以下几点:

  1. 调度:进程是拥有资源的基本单位,线程是调度和分派的基本单位。
  2. 共享地址空间:进程拥有各自独立的地址空间、资源,所以共享复杂,需要用IPC(Inter-Process Communication,进程间通信),但是同步简单。而线程共享所属进程的资源,因此共享简单,但是同步复杂,需要用加锁等措施。
  3. 占用内存和cpu:进程占用内存多,切换复杂,cpu利用率低;而线程占用内存少,切换简单,cpu利用率高。
  4. 互相影响:进程之间不会互相影响;而一个线程挂掉会导致整个进程挂掉。

三、关于僵尸进程

产生原因:当子进程比父进程先运行结束,而父进程没有回收子进程时,子进程将会成为一个僵尸进程。如果父进程先退出了,那么子进程将会被init接管,从而就不会成为僵尸进程了。

如何避免僵尸进程的产生?

解决方法有以下几种:

  1. 父进程通过wait或waitpid等待子进程结束,但是这会导致父进程挂起。
  2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,这样在子进程结束后,父进程会收到该信号,就可以在handler中调用wait回收。
  3. 若父进程不关心子进程何时结束,那么可以用 signal(SIGCHLD, SIG_IGN) 通知内核自己对于子进程的结束不感兴趣,这样子进程结束后内核会回收,并不会再给父进程发送信号。
  4. 让僵尸进程变为“孤儿进程”(即杀死其父进程),过继给1号进程init,init始终会负责清理僵尸进程。

linux下如何查看和杀死僵尸进程?

使用 top 命令可以查看当前是否存在僵尸进程,运行结果如下图:


可以看到当前系统中有6个僵尸进程,确定存在僵尸进程了,那么如何定位呢?别急,请往下看 ↓

定位僵尸进程和其父进程:ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

【注】:-A表示列出所有进程;-o 是自定义输出字段,我们设定显示字段为 stat(状态), ppid(进程父id), pid(进程id),cmd(命令)这四个参数;由于状态为 z或者Z的进程为僵尸进程,所以我们使用grep抓取stat状态为zZ进程。

运行结果如下图:


可以看到存在的6个僵尸进程的ID及其父进程的ID。

获得僵尸进程的父进程ID之后,我们就可以使用命令杀死它了。

kill -9 父进程ID

例如:kill -9 16092

如果僵尸进程多了,这样一个一个处理岂不是很慢?别着急,来个批处理命令一次搞定:

ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9

【注】:管道是 Linux 使用的主要进程间通信机制之一。一般而言,管道采用异步发送,阻塞式接收 (blocking receive) 操作,即接收进程在管道没有有效数据时被挂起等待。在 Shell中使用管道符 “|” 可以将一个命令的输出重定向到另一个命令的输入,可以嵌套运行,管道连接的每个命令程序都按一个独立进程执行, 整串命令的退出状态是最后一个命令的退出状态。

awk '{print $2}'作用是 一行一行地读取前面的查找结果,打印第二个字段(即ppid);

xargs kill -9 中的 xargs 命令是用来把前面命令的输出结果作为"kill -9"命令的参数,并执行该命令。

------------------------------------------------The end------------------------------------------------------



展开阅读全文

没有更多推荐了,返回首页