操作系统

1、线程同步的方式:互斥锁、自旋锁、读写锁、条件变量
互斥锁,访问前上锁,访问后解锁。
自旋锁的话,如果有其他任务竞争同一资源的互斥锁,则会进入循环等待过程。
读写锁。只有一个写权限,可以有多个读权限的锁,当处于写状态下,其他任何想要获取权限的请求都无法进入。而当处于读权限的时候,其他想要获取读权限的可以进行,想要获取写权限的则无法进行直到所有的读请求释放。

2、互斥锁与自旋锁的底层区别
互斥锁在等待期间会放弃CPU,而自旋锁则会一直占有CPU。

3、守护进程,孤儿进程与僵尸进程
僵尸进程,子进程先于父进程结束,但是子进程的PCB没有释放就会成为僵尸进程。僵尸进程的处理方式:
可以设置singal信号,由父进程处理,也可以由操作系统在后台处理。

孤儿进程,父进程先于子进程结束,它的那些子进程就会成为孤儿进程。孤儿进程将会被init进程(1号进程)收养,并由init进程对它们完成状态收集工作。

守护进程就是在后台运行不受终端控制的进程,一般的网络服务都是以守护进程的方式运行。守护进程脱离终端的原因,肯定是终端的有其他原因所以
1终端有在创建进程后有其他任务要做
2.终端上一些键产生的信号,不应该对之前终端启动的守护进程产生影响。
3、不希望进程执行过程中的信息在任何终端上显示

守护进程是linux中的后台服务进程,是一个生存期比较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程通常在系统引导装入时启动,在系统关闭时终止。同时守护进程还能完成很多系统任务。
在linux中每一个系统与用户进行交流的界面叫终端,每一个从终端开始运行的终端都会依附于这个终端,这个终端就称为进程的控制终端。当控制终端被关闭时,响应的进程会自动关闭。但是守护进程可以突破这阵限制,他从被执行开始运转,知道系统关闭时才推出,如果想让某个进程不因为用户或终端或其他的变化受到影响,需要把进程变成一个守护进程。

守护进程创建过程
1.调用fork创建子进程,父进程终止后,让子进程在后台继续执行
2.子进程调用setsid脱离控制终端,登陆新会话和进程组
调用setsid后会发生
a.成为新会话的首进程
b.成为一个新进程组的组长进程
c.没有控制终端

3.禁止进程重新打开控制终端:进程已经成为无终端的会话组长。但它可以重新申请一个控制终端。
4.将当前目录修改为根目录。因为从父进程继承过来的当前目录可能在一个挂在的文件系统。
5.关闭不再需要的文件描述符

4、死锁及避免
死锁出现的条件:
互斥条件,请求和保持条件,循环等待条件,不剥夺条件。
死锁的预防,破坏后三个条件即可。
避免死锁
银行家算法,保证进程处于安全进程序列,每一步都检测请求是否会造成死锁。
一次封锁法:每个进程将所有要使用的数据全部加锁。
顺序加锁法:预先对数据对象规定一个封锁顺序,所有进程都按这个顺序加锁。

5、线程上下文切换的流程
CPU进行切换的时候,通过时间片轮转算法,保存线程最后的状态,切换回来的时候加载保存的状态,能够回到上次的位置。
减少线程切换上下文的方法:不加锁并发,减少线程数量,JAVA中的CAS,使用协程
线程的几种状态

6、进程上下文切换的流程
进程的几种状态,创建,就绪,运行,阻塞,终止

7、进程的调度算法
1、FIFS先来先服务
2、SPN短任务优先原则
3、HRRN高响应比优先Highest Response Ratio Next
4.RR时间片轮转法
5、最短剩余时间优先SRT
6、多级反馈队列算法
7.最短剩余时间优先

8、虚拟内存概念(非常重要)
虚拟内存是一种内存管理技术,它在虚拟地址和物理地址之间建立映射。这样程序看到的空间是连续的,但实际上在真实的物理空间上可能是不连续的分散存储,还有可能有一部分是存储在磁盘上。
虚拟内存的优势在于
1、提供了虚拟的连续的地址空间
2、最大空间为CPU的寻址范围,超过内存的大小
CPU要访问虚拟内存是,需要通过MMU找到对应地址空间。

9、MMU地址翻译的具体流程
MMU除了地址翻译功能之外还具有地址保护功能。
首先虚拟内存划分为以页为单位,而相应的物理地址也被划分为以页框为单位。虚拟地址某个页送往MMU,MMU通过页表查到该虚拟地址对应的页框,之后将页框的起始位置和页的起始位置对应起来。如果某个页在内存中找不到对应关系,MMU会寻找通过缺页置换算法寻找一个页,将他换出内存,腾出位置,然后将空出来的页框和缺页对应起来。

虚拟地址送往MMU后,首先被分割为页号和页内地址偏移两部分,MMU会首先将页号送往快表寄存器,查看是否包含此页号的物理块号,如果包含,则直接将此物理块号送往物理地址寄存器和页内地址一起完成地址翻译。如果在快表中未找到,则MMU会先将页号和页表中的页表长度比较,如果大于等于,则会返回一个越界中断错误。如果未出现,则会将页表始址与页号和页面大小的乘积相加,从而找到该页在页表中的位置从而从中取出响应的物理块号,将物理块号和页内地址偏移一起送往物理地址寄存器,这样便完成了转换。

10、缺页处理过程

11、缺页置换算法:
最佳置换算法(理论上的算法)
先进先出置换算法
LRU置换(最近最久未使用算法)
最少使用置换算法LFT
CLOCK置换算法

13、内存页式管理
将虚拟地址划分为以页为大小的单位,同时将物理地址也划分为与页大小相同的页框为单位。通过MMU将虚拟地址和物理地址对应起来。

15、动态分区算法
1.FF首次适应算法
2.NF循环适应算法
3.BF最佳适应算法
4.WF最坏适应算法

14、int,short,long,long long类型大小。
long long 肯定是8个字节,long是long long一半4个字节,而short刚好是Long的一半2个字节。而int的话是4个字节。以上是在32和64的windows系统下。linux系统下,除了long在64位下是8个字节都一样。

15、如何判断你的电脑是32位操作系统和64位操作系统
通过void*指针大小判断,32是4字节,64是8字节

16、什么是线程池和内存池,连接池
线程池采用预先创建线程的方法,当有连接进入的时候,会从线程池中取出一个分配给它。当这个连接的任务执行完后,可以将线程放回线程池。如果有线程池的线程已经全部分配用于执行任务,则可以创建新线程。当系统空闲的时候还可以销毁部分线程。
使用线程池可以减少线程的创建和销毁。
内存池也是同样的技术,在申请的时候可以多申请部分内存,这样当下次申请的时候,如果已申请的空闲内存能够满足要求就直接从空闲内存中取下使用。

17、、什么是线程,进程和协程
进程是系统资源分配的最小单位,线程是系统调用的最小单位。
一个程序至少有一个进程,一个进程可以有多个线程。进程之间互不影响,进程有自己独立的地址空间,当一个进程崩溃的时候不会影响其他进程。
而线程是共享大部分进程的资源,自己也维护一个栈空间。当一个线程崩溃的时候整个进程都会崩溃。
协程是一种轻量化的线程,进程和线程都是系统进行管理而协程则是应用程序在管理。

协程的应用场景和优势

进程与线程的区别吗?
1、进程是资源分配最小单位,线程是程序执行的最小单位。2、进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据。3、CPU切换一个线程比切换进程花费小;创建一个线程比进程开销小。4、线程占用的资源要⽐进程少很多。5、进程对资源保护要求高,开销大,效率相对较低,线程资源保护要求不高,但开销小,效率高,可频繁切换。

18、多进程和多线程的主要区别?
线程是进程的子集(部分),一个进程可能由多个线程组成。多进程的数据是分开的、共享复杂,需要用IPC;但同步简单。多线程共享进程数据,共享简单;但同步复杂。
什么是多进程?
进程是程序在计算机上的一次执行活动,即正在运行中的应用程序,通常称为进程。当你运行一个程序,你就启动了一个进程。每个进程都有自己独立的地址空间(内存空间),每当用户启动一个进程时,操作系统就会为该进程分配一个独立的内存空间,让应用程序在这个独立的内存空间中运行。
在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态,这便是多进程,也称多任务。现代的操作系统几乎都是多任务操作系统,能够同时管理多个进程的运行。
多任务带来的好处是明显的,比如你可以边听mp3边上网,与此同时甚至可以将下载的文档打印出来,而这些任务之间丝毫不会相互干扰。
什么是多线程?
线程是一个轻量级的子进程,是最小的处理单元;是一个单独的执行路径。可以说:线程是进程的子集(部分),一个进程可能由多个线程组成。
线程是独立的。如果在一个线程中发生异常,则不会影响其他线程。它使用共享内存区域。
多线程是一种执行模型,它允许多个线程存在于进程的上下文中,以便它们独立执行但共享其进程资源。

19、进程通信方式
管道、共享内存,消息队列,信号量,消息,套接字
20、什么是管道
发送进程通过字符流形式发送大量数据进入管道,接受进程从另一端读入数据。管口一端只允许读,一端只允许写。当管道为空的时候,不允许读,当管道满的时候,不允许写。
管道分为无名管道和又名管道。无名管道常用于具有亲缘关系的父子进程之间的通信。使用时一方进程关闭读端一方关闭写端。
无名管道通过pipe函数创建的同时打开,而命名管道在mkfifo创建之后,还需要用open函数打开命名管道。

21、共享内存如何实现
共享内存是最快的IPC方式,通过共享内存,进程访问不需要通过内核,所以省去了在缓冲区之间复制的过程。
共享内存通过shmget函数创建或打开共享内存。
在linux中每个进程都有自己的PCB控制块和地址空间,页表负责在进程的虚拟地址和系统的物理地址之间进行映射,通过内存管理单元进行管理。
而共享内存就是不同进程的虚拟地址映射到同一块物理地址。
但是共享内存本身并不提供线程安全,需要采用信号量实现同步和互斥。

共享内存常见使用形式
1、使用ftok函数生成键值
每个共享内存都需要一个键值进行管理。
2、使用shmget函数创建共享内存
创建一个贡献内存标识符
3、使用shmat函数获取第一个可用共享内存空间的地址
在进程虚拟地址和共享物流地址之间确定映射关系
4、使用shmdt函数进行分离
断开进程与共享内存之间的连接
5、使用shmctl函数进行删除共享存储空间
删除共享存储空间

22、直接传递数据的高级IO函数,senfile,splice和tee
sendfile用于在两个文件描述符之间传递数据,避免了内核缓冲区和用户缓冲区之间的数据拷贝。其中in_fd必须是一个支持类似mmap函数的文件描述符,也就是必须是一个真实的文件,而不能是socket或者管道,而out_fd则必须是管道。
splice函数用于在两个文件描述符宅男移动数据,如果fd_in和fd_out之间至少有一个是管道文件描述符。
tee函数用于在两个管道文件描述符之间复制数据。

23、什么是IO复用,什么是阻塞和非阻塞。常见IO模型
IO复用就是通过管理文件描述符的方式,在一个进程或线程中处理多个IO事件。
阻塞就是程序必须按顺序执行,如果有不满足执行条件的,则会在其中滞留,等待条件满足后继续执行。非阻塞就是如果运行到某处,发现条件不满足,则系统会先处理其他任务,等到条件满足了再继续返回执行。

常见IO模型有,阻塞IO,IO复用,SIGNO信号,异步IO。
针对阻塞IO的调用如果无法立即执行,则会被系统挂起,直到等待的事件发生,而非阻塞IO执行的系统调用总是立即返回。
IO复用,就是能够同时阻塞多个IO操作,同时对读和写进行检测,当检测到有读或者写的时候,返回可用的套接字。
select的问题在于每次返回后都要重新设置,以便下次检测,可监测的IO操作有限,最多有1024个。select维护的是一个线性表。
poll函数则是一个结构体,包含套接字和注册事件和发生事件,返回后不用重新设置事件。也不再受限于1024的数量。poll维护的是一个链表。
select和poll每次都要在内核和用户区之间拷贝,而且都要轮询去查看到底是哪个是socket发生了事件。而epoll维护的是红黑树。
而epoll函数则是直接在内核中设置,返回的时候是返回发生事件的一系列套接字而不用轮询检查。
有时候select优于epoll,因为epoll通知的时候使用函数回调,所以在连接数比较少,以及每个连接都很活跃的情况下,反而select比较好。

SIGNO信号,信号触发读写就绪事件,用户执行读写事件。程序没有阻塞阶段。
异步IO,内核执行读写并触发读写完成事件,程序没有阻塞阶段。

24、硬中断和软中断
由系统相连的外设产生的,用来通知操作系统外设状态的变化。
硬中断用来处理那些短时间就是可以完成的工作,而那些处理时间较长的工作就放到中断之后来完成也就是软中断。
硬中断和软中断的区别
1.硬中断是外设引发的,软中断是执行中断指令产生的。
2.硬中断的中断号是中断控制器提供的,软中断的中断的中断号是由指令直接指出。
3.硬中断是可屏蔽的,软中断不可屏蔽。
4.硬中断处理程序要求他能快速的完成任务,这样程序执行时才不会等待较长时间,称为上半部。
软中断处理中断未完成的工作,是一种推后执行的机制,属于下半部。
硬中断和软中断的区别

26、通过共享内存和管道分别几次内核态和用户态的交互?
普通通信方式需要两次用户态和内核态之间的交互,一次从进程到内核,一次从内核到缓冲区。(消息队列也假设是如此)
而共享内存是把一块内存空间映射到共享他的不同进程的内存空间,所以进程只需要访问自己的内存空间就可以了。

30、半连接队列都消耗了Linux什么系统资源?

31、grep 命令的作用是什么?
grep在文件中查找指定字符串模板

32、Linux文件系统怎么实现

33、用户态和内核态
内核态:CPU可以访问内存的所有数据,包括外围设备:硬盘,网卡等,CPU可以自己从一个程序切换到另一个程序

用户态:只能受限的访问内存,且不允许访问外围设备,占用CPU的能力被剥夺,CPU资源可以被其他程序获取。

为了需要限制不同程序之间的访问能力,防止他们获取别的程序的内存数据或者获取外围设备的数据,并发送到并网络。

内核态和用户态之间的切换有三种方式
1、系统调用
这是用户进程主动要求切换到内核态的方式,用户态进程通过系统调用使用操作系统提供的服务完成工作。
2.异常
CPU执行在用户态尘程序时,发生了某些不可知的异常,会触发。当前进程会切换到处理此异常的内核相关程序中,转到内核态,比如缺页异常。
3.外围设备中断
当外围设备完成用户的请求操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将执行的指令,从而去执行要中断信号对应的处理程序。

Reactor模式(核反应堆)
Reactor要求主线程只负责监听文件描述符是否有事件发生,有的话 立即将该事件通知工作线程。主线程不做任何其他工作,读写数据接受新的请求以及处理客户请求都在工作线程中完成

使用同步IO模型
1.主线程往epoll内核时间表中注册socket上的读就绪事件。
2、主线程调用epoll_wati等待sokcet上有数据可读。
3、当socket上有数据可读,epoll_wait通知主线程。主线程将socket可读时间放入请求队列。
4、水淼在请求队列上的某个工作线程被唤醒,他从socket读取,并处理客户请求,然后往epoll内核事件表中注册socket写就绪事件。
5、主线程调用epoll_wati等待socket可写。
6、当socket可写时,epoll_wait通知主线程。主线程将socket可写事件放入请求队列
7、睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务处理客户请求的结果。

Proactor将所有IO操作都交给主线程和IO完成,工作线程仅仅如则业务逻辑
使用异步IO模型
1、主线程调用aio_read想内核注册socket上读完成事件,并告诉内核用户缓冲区位置和读操作完成时如何通知应用程序。
2、主线程继续其他逻辑
3、当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以通知i应用程序可用。
4、应用程序预先定好的信号处理函数会选择一个工作线程来处理客户请求。工作线程处理完客户请求后,调用aio_write函数向内核注册socket写完成事件,并告诉内核用户缓冲区位置,以及写操作完成时如何通知应用程序
5、主线程继续处理其他逻辑
6、当用户缓冲区的数据被写入socket后,内核将向应用程序发送一个信号,以通知应用程序数据发送完毕
7、应用程序预定定义好信号处理函数选择工作线程来善后

同步模拟proactor和异步模拟proactor的区别在于是谁处理IO,是内核还是主线程。

半同步/半异步模式
这里同步指的是程序执行按照代码序列执行,异步指的是程序执行需要由系统事件来驱动。半同步/半异步模式,就是同步线程用于处理客户逻辑,异步线程用于处理IO事件。异步线程监听到客户请求后就将其封装成请求对象插入请求队列。请求队列将通知某个工作在同步模式下的工作线程来处理该请求。

半同步/半异步反应堆模式
异步线程只有一个,由主线程来充当。他负责监听所有socket上的事件,如果监听的socket有可读时间,主线程就接受新的连接socket,然后往epoll内核事件表注册该socket上的读写事件。如果连接socket上有读写事件发生,即有新的客户请求到来或有数据要发送到客户端。主线程就将该socket插入到请求队列中。所有工作线程都睡眠在请求队列上,当有任务到来时他,他们通过竞争获得任务接管权。
问题在于,主线程和工作线程共享 请求队列。主线程向请求队列加入任何,工作线程从请求队列取出任务都需要加锁,浪费CPU资源。
2、每个工作线程同一时间只能处理一个客户请求。如果客户数量较多,而工作线程较少,而请求队列中将队堆积很多任务对象。客户端的响应速度将越来越慢。

高效的半同步/半异步模式
每个工作线程能同时处理多个客户连接。
主线程只管监听socket,当有新的连接到来,主线程就接受并返回新的socket连接给某个工作线程。然后改socket上任何IO操作都由工作线程来处理,直到客户关闭连接。

领导者/追随者模式
领导者/追随者模式是多个工作线程轮流获得事件源集合,轮流监听,分发并处理时间的一种模式。在任意时间点,程序都仅有一个领导者线程,他负责监听IO事件,而其他线程都是追随者。他们休眠在线程池中等待称为新的领导者,当前领导者如果检测到IO事件,首先要从线程池中选出新的领导者,然后处理IO事件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值