整理OS进程与线程的相关问题

前文:

通过博客记录在准备面试过程中遇到的问题,重要是通过分析各类文档去自己总结,如果有问题欢迎指出。

正文:

OS中进程与线程的问题在面试中经常会问到。尤其最近准备运维工程师的面试,发现Linux相关的问题,除了常见指令的考察,这方面的问题应该算是最常问到的了。所以,我查阅了很多文档,并作出总结。

1.进程与线程的定义及区别

百度百科:
进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

总结:进程(process)是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。而进程中所包含的一个或多个执行单元称为线程(thread),或者说线程是进程之内独立执行的一个单元执行流。

进程与线程的区别
有以上信息,可以知道,线程其实包含在进程的概念里。这里需要注意的是进程是线程的容器,所以说不存在没有线程的进程的。
进程是资源分配的最小单位,线程是程序执行的最小单位。

  • 拥有资源 :进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
  • 通信方式:线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。这一点会在后面展开说。
  • 并发:在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,因而使操作系统具有更好的并发性,从而能更有效地使用系统资源和提高系统吞吐量。
  • 系统开销:由于在创建或撤消进程时,系统都要为之分配或回收资源,因此,操作系统所付出的开销将显著地大于在创建或撤消线程时的开销。进程切换的开销也远大于线程切换的开销。

2.进程和线程的状态

这个问题在阅读相关文档时,发现很多人对进程和线程的概念是混淆的。这里进程状态我用Linux进程的状态来解答,然后再补充线程的五个状态。
(1)Linux的七种状态
R运行状态(runing):并不意味着进程一定在运行中,也可以在运行队列里;
S睡眠状态(sleeping):进程在等待事件完成;(浅度睡眠,可以被唤醒)
D磁盘睡眠状态(Disk sleep):不可中断睡眠(深度睡眠,不可以被唤醒,通常在磁盘写入时发生)
T停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止进程,可以发送SIGCONT信号让进程继续运行
X死亡状态(dead):该状态是返回状态,在任务列表中看不到;
Z僵尸状态(zombie):子进程退出,父进程还在运行,但是父进程没有读到子进程的退出状态,子进程进入僵尸状态;
t追踪停止状态(trancing stop)
(2)进程的五种状态
整理OS进程与线程的相关问题_第1张图片

  • 新生状态(New)
    用new关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。

  • 就绪状态(Runnable)
    处于就绪状态的线程已经具备了运行条件,但是还没有被分配到CPU,处于“线程就绪队列”,等待系统为其分配CPU。就绪状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会进入执行状态。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。有4中原因会导致线程进入就绪状态:

    1. 新建线程:调用start()方法,进入就绪状态;
    2. 阻塞线程:阻塞解除,进入就绪状态;
    3. 运行线程:调用yield()方法,直接进入就绪状态;
    4. 运行线程:JVM将CPU资源从本线程切换到其他线程。
  • 运行状态(Running)
    在运行状态的线程执行自己run方法中的代码,直到调用其他方法而终止或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态。也可能由于某些“导致阻塞的事件”而进入阻塞状态。

  • 阻塞状态(Blocked)
    阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪)。有4种原因会导致阻塞:

    1. 执行sleep(int millsecond)方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。
    2. 执行wait()方法,使当前线程进入阻塞状态。当使用nofity()方法唤醒这个线程后,它进入就绪状态。
    3. 线程运行时,某个操作进入阻塞状态,比如执行IO流操作(read()/write()方法本身就是阻塞的方法)。只有当引起该操作阻塞的原因消失后,线程进入就绪状态。
    4. join()线程联合: 当某个线程等待另一个线程执行结束后,才能继续执行时,使用join()方法。
  • 死亡状态(Terminated)
    死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它run()方法内的全部工作; 另一个是线程被强制终止,如通过执行stop()或destroy()方法来终止一个线程(注:stop()/destroy()方法已经被JDK废弃,不推荐使用)。

3.进程间通信方式

(1) 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。

(2)有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。

(3)信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

(4)消息队列(message queue):消息队列是由消息组成的链表,存放在内核中 并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

(5)信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某一事件已经发生。

(6)共享内存(shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式,它是针对其他进程间的通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。

(7)套接字(socket):套接口也是一种进程间的通信机制,与其他通信机制不同的是它可以用于不同及其间的进程通信。

你可能感兴趣的:(操作系统,java,linux,运维)