加入收藏 | 设为首页 | 会员中心 | 我要投稿 我爱制作网_池州站长网 (https://www.0566zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

操作系统

发布时间:2022-10-24 14:59:42 所属栏目:Unix 来源:
导读:  进程有那些状态?

  答:

  进程间的通信方式

  1. 管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。

  2. 有名管道(Names Pipes) : 匿名管道由于没有名字
  进程有那些状态?
 
  答:
 
  进程间的通信方式
 
  1. 管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
 
  2. 有名管道(Names Pipes) : 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循先进先出(first in first out)。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。
 
  3. 信号(Signal) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
 
  4. 消息队列(Message Queuing) :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺。
 
  5. 信号量(Semaphores) :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
 
  6. 共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。
 
  7. 套接字(Sockets) :此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
 
  线程之间的通信方式?
 
  答:
 
  1. 共享内存:线程之间共享程序的公共状态,线程之间通过读-写内存中的公共状态来隐式通信。volatile共享内存
 
  2. 消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显示的进行通信。wait/notify等待通知方式、join方式
 
  3. 使用阻塞队列控制线程通信:管道输入/输出流的形式
 
  4.使用管道流进行线程通信(已被上面的阻塞队列代替)
 
  通过输入/输出在线程间进行通信通常很有用。Java中对应的实现就是PipedWriter类和PipedReader类。这种使用管道来通信的模型可以看成是"生产者-消费者"问题的变种,这里的管道就是一个封装好的解决方案。管道基本上就是一个阻塞队列,它存在于引入阻塞队列之前的java版本中。在实际开发中,很少会使用到管道流。
 
  用户级线程和内核级线程?
 
  答:
 
  用户级线程和内核级线程
 
  用户级线程和内核级线程
 
  线程的同步方式?
 
  1. 互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
 
  2. 信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
 
  3. 事件(Event) :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操
 
  操作系统中进程的调度算法有哪些吗?
 
  过程:
 
  1、按照先来先服务原则排序,设置N个就绪队列为Q1,Q2...QN,每个队列中都可以放很多作业;
 
  2、为这N个就绪队列赋予不同的优先级,第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低;
 
  3、设置每个就绪队列的时间片,优先权越高,算法赋予队列的时间片越小。时间片大小的设定按照实际作业(进程)的需要调整;
 
  4、进程在进入待调度的队列等待时,首先进入优先级最高的Q1等待。
 
  5、首先调度优先级高的队列中的进程。若高优先级中队列中已没有调度的进程,则调度次优先级队列中的进程。例如:Q1,Q2,Q3三个队列,只有在Q1中没有进程等待时才去调度Q2,同理,只有Q1,Q2都为空时才会去调度Q3。
 
  6、对于同一个队列中的各个进程,按照时间片轮转法调度。比如Q1队列的时间片为N,那么Q1中的作业在经历了时间片为N的时间后,若还没有完成,则进入Q2队列等待,若Q2的时间片用完后作业还不能完成,一直进入下一级队列,直至完成。
 
  7、在低优先级的队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业即抢占式调度CPU。
 
  多线程和多进程区别?
 
  答:
 
  线程(CPU调度和分派的基本单位)是进程(操作系统进行资源分配和调度的基本单位)划分成的更小的运行单位,一个进程在其执行的过程中可以产生多个线程。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。线程执行开销小,但不利于资源的管理和保护;而进程正相反,并且线程中内存地址空间是相互共享的,而进程中不是。因此,进程和线程其实都是内核调度实体(KSE),只是对?些系统资源,例如虚拟内存、打开?件描述符、对信号的处置、进程 ID 等资源的共享程度不同?已。所以我们可以推断出以下结论:
 
  线程间的通信更容易,因为拥有着同?块数据段,因?可以使?全局变量进?通信,相当于继承,大家公用一部分资源。线程的创建速度要高于进程,因为“数据重合度”更?,?线程只需要拥有??的程序计数器,一组寄存器和栈即可(1、程序计数器为什么是私有的?程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。2、栈为什么是私有的?保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。)线程之间的上下?切换也要?进程间的上下?切换更快,因为线程更加轻量,自然在切换的过程中消耗的资源也更少(什么是上下文切换?线程切换意味着需要保存当前线程的上下文,留待线程下次占用 CPU 的时候恢复现场。并加载下一个将要占用 CPU 的线程上下文。这就是所谓的 上下文切换。)。线程同步的时候需要同步机制来支持,因为资源共享,我们在共享资源操作的时候,需要加额外的操作,但是进程不用,进程的资源是独立的,同步的时候更加容易协程和线程区别?
 
  答:
 
  并发和并行的区别
 
  就想前面提到的操作系统的时间片分时调度。打游戏和听音乐两件事情在同一个时间段内都是在同一台电脑上完成了从开始到结束的动作。那么,就可以说听音乐和打游戏是并发的。
 
  这里面有一个很重要的点,那就是系统要有多个CPU才会出现并行。在有多个CPU的情况下,才会出现真正意义上的『同时进行』。
 
  什么是僵尸进程?
 
  答:僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出,子进程被init接管,子进程推出后init会回收其占用的相关资源。如果太多僵尸进程的话,会导致系统的进程号不够用,不再产生进程。解决方法: (1) 让僵尸进程成为孤儿进程,由init进程回收;(手动杀死父进程)。(2) 父进程用wait或waitpid去回收资源(方案不好)父进程通过wait或waitpid等函数去等待子进程结束,但是不好,会导致父进程一直等待被挂起,相当于一个进程在干活,没有起到多进程的作用。
 
  线程死锁是如何产生的,如何避免 ?
 
  答:
 
  互斥条件:一个资源在同一时刻只由一个线程占用。请求与保持条件:一个线程在请求被占资源时发生阻塞,并对已获得的资源保持不放。循环等待条件:发生死锁时,所有的线程会形成一个死循环,一直阻塞。不剥夺条件:线程已获得的资源在未使用完不能被其他线程剥夺,只能由自己使用完释放资源。破坏互斥条件:使资源同时访问而非互斥使用,就没有进程会阻塞在资源上,从而不发生死锁。但是这种场景很少,因为你资源共享的话,如果是只读就可以,但是设计到修改很可能会导致异常。而且我们加锁就是为了互斥。破坏占有和等待条件:采用静态分配的方式,静态分配的方式是指进程必须在执行之前就申请需要的全部资源,且直至所要的资源全部得到满足后才开始执行。占有部分资源的线程进一步申请其他资源时,如果申请不到,主动释放它占有的资源,破坏 "不可抢占" 条件按序申请资源,破坏 "循环等待" 条件io多路复用,介绍select,poll,epoll原理unix线程切换,他们的优缺点及不同?手写死锁?
 
      Lock lock1 = new ReentrantLock();
      Lock lock2 = new ReentrantLock();
      static Runnable a = () -> {
          try {
              while (true) {
                  HashMap objectObjectHashMap = new HashMap<>();
  //                    lock1.lock();
                  synchronized (test.obj1) {
                      System.out.println("Thread 1 lock 1");
                      Thread.sleep(5000);
  //                        lock2.lock();
                      synchronized (test.obj2) {
                          System.out.println("Thread 1 lock 2");
                          Thread.sleep(5000);
                      }
  //                        lock2.unlock();
                      System.out.println("Thread 1 unlock 2");
  //                        lock1.unlock();
                  }
                  System.out.println("Thread 1 unlock 1");
              }
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      };
      static Thread thread1 = new Thread(a);
      static Thread thread2 = new Thread(() -> {
          try {
              while (true) {
  //                    lock2.lock();
                  synchronized (test.obj2) {
                      System.out.println("Thread 2 lock 2");
                      Thread.sleep(5000);
  //                    lock1.lock();
                      synchronized (test.obj1) {
                          System.out.println("Thread 2 lock 1");
                          Thread.sleep(5000);
                      }
  //                    lock1.unlock();
                      System.out.println("Thread 2 unlock 1");
  //                    lock2.unlock();
                  }
                  System.out.println("Thread 2 unlock 2");
              }
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      });
      
      public static String obj1 = "obj1";
      public static String obj2 = "obj2";
      public static void main(String[] args) {
          thread1.start();
          thread2.start();
      }
  简述操作系统如何进行内存管理?
 
  答:
 
  参考链接
 
  简述操作系统中的缺页中断?
 
  答:
 
  什么时候会由用户态陷入内核态?
 
  答:
 
  系统调用(trap)、中断(interrupt)和异常(exception)。
 
  系统调用是用户进程主动发起的操作。发起系统调用,陷入内核,由操作系统执行系统调用,然后再返回到进程。
 
  中断和异常是被动的,无法预测发生时机。中断包括 I/O 中断、外部信号中断、各种定时器引起的时钟中断等。异常包括程序运算引起的各种错误如除 0、缓冲区溢出、缺页等。
 
  在系统的处理上,中断和异常类似,都是通过中断向量表来找到相应的处理程序进行处理。区别在于,中断来自处理器外部,不是由任何一条专门的指令造成,而异常是执行当前指令的结果。
 
  操作系统中,虚拟地址与物理地址之间如何映射?Linux 下如何查看端口被哪个进程占用?
 
  答:lsof -i:端口号
 
  进程通信中的管道实现原理是什么?
 
  答:
 
  Linux 下如何排查 CPU 以及 内存占用过多?
 
  答:CPU的话使用TOP命令去查一下哪些线程
 
  简述 Linux 虚拟内存的页面置换算法?简述 Linux 零拷贝的原理?
 
  答:
 
  参考文章
 
  Linux 中虚拟内存和物理内存有什么区别?有什么优点?BIO、NIO 有什么区别?怎么判断写文件时 Buffer 已经写满?简述 Linux 的 IO模型简述 mmap 的使用场景以及原理?简述操作系统中 malloc 的实现原理?LVS 的 NAT、TUN、DR 原理及区别?
 

(编辑:我爱制作网_池州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章