• 笔、面试时OS常见题目【转】【Updating】


    原文:

    http://289972458.iteye.com/blog/1326406

    1、线程与进程的区别联系

    2、进程通信方式有哪些?

    3、同步的方式有哪些?

    4、ThreadLocal与其它同步机制的比较

    5、进程死锁的条件

    6.进程间状态切换-待更新 

    第一题:

    对于线程,进程的概念一直都是比较模糊,最近整理了一下。总结起来就是,线程是进程的一部分,进程是程序的一部分。这个说法不准确,但是可以指出期间的差别;

    进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

    一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。线程的引入:例如,有一个Web服务器要进程的方式并发地处理来自不同用户的网页访问请求的话,可以创建父进程和多个子进程的方式来进行处理,但是创建一个进程要花费较大的系统开销和占用较多的资源。除外,这些不同的用户子进程在执行的时候涉及到进程上下文切换,上下文切换是一个复杂的过程。所以,为了减少进程切换和创建的开销,提高执行效率和节省资源,人们在操作系统中引入了"线程(thread)"的概念。

    进程的作用和定义:进程是为了提高CPU的执行效率,减少因为程序等待带来的CPU空转以及其他计算机软硬件资源的浪费而提出来的。进程是为了完成用户任务所需要的程序的一次执行过程和为其分配资源的一个基本单位,是一个具有独立功能的程序段对某个数据集的一次执行活动。

    线程和进程的区别:
    1、 线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。
    2、 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
    3、 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
    4、 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。
    5、 进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。
     
    进程与程序的区别:
    程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般说来,一个进程肯定与一个程序相对应,并且只有一个,但是一个程序可以有多个进程,或者一个进程都没有也可以只有一个进程。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候会产生进程。总结:线程是进程的一部分,进程是程序的一部分。

    前一句说的不太准确,线程也有自己的资源,比如栈,私有数据等等。说他使用而不拥有资源指的是使用的是进程的打开文件句柄,进程的全局数据,进程的地址空间等等,这些都属于进程,而不属于线程,进程内个线程共享。

    进程切换比线程切换开销大是因为进程切换时要切页表,而且往往伴随着页调度,因为进程的数据段代码段要换出去,以便把将要执行的进程的内容换进来。本来进程的内容就是线程的超集。而且线程只需要保存线程的上下文(相关寄存器状态和栈的信息)就好了,动作很小。

    第二题:


    进程间通讯的方式:

    • 管道中还有命名管道和非命名管道之分,非命名管道只能用于父子进程通讯,命名管道可用于非父子进程,命名管道就是FIFO,管道是先进先出的通讯方式。FIFO是一种先进先出的队列。它类似于一个管道,只允许数据的单向流动。每个FIFO都有一个名字,允许不相关的进程访问同一个FIFO,因此也成为命名管。
    • 消息队列:是用于两个进程之间的通讯,首先在一个进程中创建一个消息队列,然后再往消息队列中写数据,而另一个进程则从那个消息队列中取数据。需要注意的是,消息队列是用创建文件的方式建立的,如果一个进程向某个消息队列中写入了数据之后,另一个进程并没有取出数据,即使向消息队列中写数据的进程已经结束,保存在消息队列中的数据并没有消失,也就是说下次再从这个消息队列读数据的时候,就是上次的数据!!!
    • 信号量,不能传递复杂消息,只能用来同步
    • 共享内存,只要首先创建一个共享内存区,其它进程按照一定的步骤就能访问到这个共享内存区中的数据,当然可读可写;

    几种方式的比较:

    • 管道:速度慢,容量有限
    • 消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题。
    • 信号量:不能传递复杂消息,只能用来同步
    • 共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了一块内存的。


    第三题:

    线程同步指多个线程同时访问某资源时,采用一系列的机制以保证同时最多只能一个线程访问该资源。线程同步是多线程中必须考虑和解决的问题,因为很可能发生多个线程同时访问(主要是写操作)同一资源,如果不进行线程同步,很可能会引起数据混乱,造成线程死锁等问题;


    线程同步的方式:

    • 临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问
    • 互斥量:为协调共同对一个共享资源的单独访问而设计的
    • 信号量:为控制一个具有有限数量用户资源而设计
    • 事件:用来通知线程有一些事件已发生,从而启动后继任务的开始

    总结比较:

    • 互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。
    • 互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和线程退出。
    • 通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数器。


    第四题:


    ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致地分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进ThreadLocal。由于ThreadLocal中可以持有任何类型的对象,所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本(1.5)将模版的引入,新的支持模版参数的ThreadLocal<T>类将从中受益。也可以减少强制类型转换,并将一些错误检查提前到了编译期,将一定程度地简化ThreadLocal的使用。


    总结:当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序,使程序更加易读、简洁。



    第五题:


    什么是死锁?如果一个进程集合里面的每个进程都在等待只能由这个集合中的其他一个进程(包括他自身)才能引发的事件,这种情况就是死锁;


    这个定义可能有点拗口,一个最简单的例子就是有资源A和资源B,都是不可剥夺资源,现在进程C已经申请了资源A,进程D也申请了资源B,进程C接下来的操作需要用到资源B,而进程D恰好也在申请资源A,那么就引发了死锁。这个肯定每个人都看过了。然后套用回去定义:如果一个进程集合里面(进程C和进程D)的每个进程(进程C和进程D)都在等待只能由这个集合中的其他一个进程(对于进程C,他在等进程D;对于进程D,他在等进程C)才能引发的事件(释放相应资源);


    这里的资源包括了软的资源(代码块)和硬的资源(例如扫描仪)。资源一般可以分两种:可剥夺资源(Preemptable)和不可剥夺资源(Nonpreemptable)。一般来说对于由可剥夺资源引起的死锁可以由系统的重新分配资源来解决,所以一般来说大家说的死锁都是由于不可剥夺资源所引起的;


    死锁的四个必要条件:

    • 互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
    • 请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
    • 非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
    • 循环等待条件(Circular wait):系统中若干进程组成环路,改环路中每个进程都在等待相邻进程正占用的资源。

    处理死锁的策略:

    • 忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像;
    • 检测死锁并且恢复;
    • 仔细地对资源进行动态分配,以避免死锁;
    • 通过破除死锁四个必要条件之一,来防止死锁产生;
  • 相关阅读:
    Golang的math包常用方法
    部署tomcat部署实战案例
    CentOS 7.6操作系统部署JDK实战案例
    Linux防火墙iptables命令管理入门
    Docker镜像-基于DockerFile制作编译版nginx镜像
    使用Docker快速部署Mysql服务器
    Docker镜像-基于DockerFile制作yum版nginx镜像
    Docker镜像-手动制作yum版nginx镜像
    Docker容器操作基础命令
    Docker镜像管理篇
  • 原文地址:https://www.cnblogs.com/xiawen/p/3114904.html
Copyright © 2020-2023  润新知