Linux系统八股

69 阅读14分钟

 线程和进程的区别

进程是系统资源分配和调度的基本单位,而线程是程序运行的最小单位,线程是进程的子任务,一个进程至少有一个线程,而且一个进程可以同时运行多个线程,这些线程共享一块内存。

在资源开销上,由于每个进程就有独立空间,因此创建和销毁进程的开销比较大,在进程间切换中需要保存、恢复整个进程的状态,对此上下文切换开销较大。由于线程共享相同的内存空间,因此创建和销毁进程的开销比较小,在线程间切换中需要保存、恢复线程少量上下文信息即可,上下文切换开销比较小。

在通信方面,进程间相互隔离,需要通过一些特殊方式进行通信,比如:消息队列、管道、共享内存等,而由于线程共享相同的内存空间,可以直接进行访问共享数据,通向更加方便。

在安全性上,由于进程间互相隔离,一个进程的奔溃不会直接影响到其他进程的稳定性,而对于线程共享相同的内存空间,一个线程的奔溃可能会影响整个进程的稳定性。

并行和并发有什么区别

并行是指在同一时刻内执行多个任务,这些任务可以同时执行,每个任务在不同的处理核心上,比如多个CPU核心执行,在并行系统中,多个处理核心可以同时处理独立的子任务,从而加快整体任务的完成。

并发是指在相同时间段内执行多个任务,这些任务不可能同时发生,而是交替执行,通过时间片轮或事件驱动方式。并发通常和任务的交替执行和任务调度有关。

解释一下用户态和核心态

用户态和核心态是操作系统为了维护系统资源和管理权限控制而设计的两种不同CPU处理级别,可以控制进程或者程序对计算机硬件资源的访问权限和操作范围。

在用户态,只能访问受限的资源和运行受限的指令集,不能直接访问操作系统的核心部分,也不能直接访问硬件资源,而内核态属于操作系统的特权级别,可以运行特权的指令和访问操作系统的核心部分,在内核态中,可以访问硬件资源,也可以进行系统调用、管理内存、文件操作等操作

用户态和内核态切换主要发生在系统调用、异常、中断场景。当用户程序请求操作系统的提供的服务时,会通过系统调用进入内核态;当程序执行过程种出现错误或者异常,CPU会自动从用户态切换到内核态,以便于操作系统处理这些异常,还有一种就是当外部设备,比如键盘、鼠标、硬盘等出现中断,发送中断信号会引起CPU切换到内核态,操作系统处理这些中断,并且执行中断对应的程序,然后CPU会切换到用户态

进程调度算法你了解多少

我大概了解六种,第一种是"先来先服务",通过请求顺序进行调度,这种调度算法简单,但是会导致较长任务阻塞较短任务。第二种是"最短任务优先",是根据进程的最短执行时间调用,但是如果出现一直有短任务到来,则长任务一直得不到调度,会出现长任务"饥饿"的现象。第三种是"最短剩余时间优先",是在最短任务的基础优化,按照剩余时间的顺序进行调度,当一个新进程到来时,会根据新进程运行时间和当前进程剩余时间进行对比,如果新进程执行时间较短,则将当前进程挂起,执行新进程,否则挂起新进程。第四种是"优先级调度",是为每个进程分配优先级,根据优先级进行调度,为了避免低优先级的进程永远得不到调用,则随着时间的推移,增加等待队列进程的优先级。第五种是"时间片轮转",为每个进程分配时间片,进程轮流执行,当时间片结束,则切换下一个进程。第六种是"多级队列",是时间片轮转调度算法和优先级调度算法的结合,将进程分为不同的队列种,每个队列都有自己的调度算法。

进程间有哪里通信方式

主要有九种通信方式,分别是管道、命令管道、消息队列、信号、信号量、共享内存、互斥锁、条件变量、Socket套接字。管道是一种半双工的通信方式,数据只能单向流动而且只能由存在父子进程关系的进程间通信。命令管道类似管道、也是半双工的通信方式,他允许不相关的进程间进行通信。消息队列是运行进程可以发送和接收信息、消息队列是消息的链表,存在优先级。信号是发送通知进程,发生了什么事件或者条件。信号量是一个计数器,用于控制多个进程访问共享内存,是一种常见的锁机制,防止某个进程访问共享数据,其他进程也想访问该数据,主要用于进程间及其一个进程中多个线程间同步的手段。共享内存是一段映射的内存能被其他进程访问,是由一个进程创建,其他进程可以访问,共享内存是最快的进程通信方式,是互斥锁是一种信号量,用于保护共享的数据结构数据,避免多个进程同时访问。条件变量通过同互斥锁搭配使用,等待进程同步或者条件的发生。Socket套接字,作为TCP/IP网络通信的基本操作单位,主要用于服务端和客户端之间网络通信。

解释一下进程同步和互斥,以及如何实现进程同步和互斥

进程同步是指多个并发执行的进程之间协调和管理它们的执行顺序,按照一定的顺序和时间间隔执行。

进程互斥是某一时刻只允许一个进程访问某个共享资源,当一个进程访问该共享资源,其他进程不能同时访问该资源。

解决进程同步和互斥,通常采用信号量和PV操作实现。信号量是一种特殊的变量,表示系统中某种资源的数量或状态,PV操作是一种对信号量进行增加或者减少的操作,它们控制着进程同步或者互斥。

P操作类似"检查"信号量,发现资源可用,减少计数,然后使用该资源

V操作类似"归还"信号量,增加计数,可能引起等待进程的唤醒

以下三种也可以解决进程同步和互斥问题:临界区,临界区是可能会出现互斥的代码区域称为临界区,进入临界区需要获得一把锁,离开临界区释放锁,确保同一时刻只有一个进程访问共享资源。然后就是互斥锁,互斥锁是是一种同步机制,用于实现互斥,每个共享资源都关联一把互斥锁,只有获得互斥锁才能访问共享资源,离开需要释放锁,确保同一时刻只有一个进程访问共享资源,最后就是条件变量,主要在进程间的信息传递,以便于在特定条件下等待或者唤醒进程,通常搭配互斥锁使用,确保在正确的时机进行进程等待或者唤醒。

什么是死锁,如何预防死锁

死锁是指两个或多个进程执行过程中,因抢夺资源而导致的一种僵局,当每个进程持有一定的资源并且等待其他进程释放所需要的资源,如果这些资源被其他进程占有并且不释放,则导致死锁。

死锁需要满足以下四个条件:

第一个就是互斥条件,一个进程占有某个共享资源,其他进程不能同时占有该资源

第二个是请求保持条件,一个线程因为请求资源而阻塞时候,不会释放自己的资源

第三个是不可剥夺条件,不能强制性从一个进程中剥夺资源,只能由持有者自愿释放

第四个是循环等待条件,多个进程之间形成一个循环等待资源的链,每个进程都在等待下一个进程所占有的资源

预防死锁方面,我们可以采取破坏形成死锁的四个必要条件之一即可,比如破坏循环等待条件,让所有进程按照相同的顺序请求资源,在检测死锁方面,可以通过检测系统中资源的分配情况判断是否存在死锁,比如,可以通过资源分配图或银行家算法检测,在解除死锁中,如果出现死锁,可以采取抢占资源、终止某个进程或资源回收等方式解除死锁。

你知道的线程同步的方式有哪些?

线程同步机制是指在多线程编程中,防止多线程互相干扰,而采用的一种线程同步机制。以下是常见的四种线程同步的方式:

第一种,互斥锁,互斥锁是常见的线程同步的方式,只允许一个线程同时对共享资源的访问。第二种,条件变量,用于线程间的消息传递,允许一个线程可以等待某个条件的满足,其他线程可以发送通知等待线程,通常与互斥锁一起使用。第三种,读写锁,允许多个线程同时读取共享资源,只能一个线程写入资源。第四种,信号量,控制多线程进行共享资源的访问的工具

讲一讲你理解的虚拟内存

虚拟内存是指每个进程在创建加载过程,系统分配的一段连续地址空间,它们并不是真实存在的,而是通过映射与实际物理地址空间对应,使得每个进程看起来都有自己独立的连续地址空间,允许程序使用比物理内存RAM更多的内存,使得程序认为有足够的内存运行。

以下是需要虚拟内存的原因:第一个原因是内存扩展,虚拟内存运行程序使用实际可用内存更多的内存,从而执行更大的程序或处理更多的数据。第二个原因是内存隔离,虚拟内存为每个进程提供了内存隔离,每个进程都有属于独立的连续地址空间,一个进程无法直接访问到其他进程的内存。第三个原因是物理内存管理,虚拟内存允许操作系统动态地将数据和程序部分先加载到物理内存中,以满足当前进程的需求,当物理内存不足时,操作系统将不常用的数据和程序挂起到硬盘,释放当前内存,确保进程的正常运行。第四个原因是页面交换,当物理内存不足时,可用将物理内存中数据先写入在硬盘的虚拟内存中,这个过程成为页面交换,当需要该数据可用通过虚拟内存重新加载物理内存中,确保进程的正确运行,尽管物理内存有限。第五个原因是文件操作,虚拟内存还可以用于文件映射到内存中,使得文件的读写操作像内存一样高效。

介绍一下集中典型的锁

互斥锁:是一种常见的锁类型,用于互斥访问共享资源。线程需要获得互斥锁才能访问共享资源,只有一个线程可以持有互斥锁,其他线程只能等待互斥锁被释放,确保了只有一个线程在访问共享资源。

自转锁:属于一种忙于等待的锁,既线程在尝试获得锁时会不断轮询,直到锁被释放。

其他锁也是基于以上两种锁,比如读写锁,乐观锁和悲观锁。

读写锁:运行多线程同时读取共享资源,而只允许一个线程进行写操作,存在读和写两种状态。

乐观锁:属于先修改了共享资源,如果有线程同时修改了共享资源,则撤回本次修改。

悲观锁:认为多线程出现冲突概率比较大,每次访问都需要上锁。

有哪些页面置换算法

我所理解的页面置换算法有最近最久未使用算法(LRU)、最不经常使用算法(LFU)、时钟算法(clock)、先进先出(FIFO)、最佳置换算法(opt)

最近最久未使用算法(LRU)是基于页面的使用历史,通过选择最长时间未被使用的页面进行置换

最不经常使用算法(LFU)是根据页面的访问频率,淘汰访问次数最少的页面

先进先出(FIFO)是根据先进入内存的页面先被置换出去

时钟算法:算法核心是是通过一个指针,称为时钟指针,用于遍历一个环形链表,检查页面是否被访问过,当需要页面置换时,会从时钟指针的位置开始遍历环形链表。当访问位为1,表示页面最近被访问过,属于活跃状态,当访问位为0,表示页面最久没有被访问过,可以选择发生置换。将访问位设置为1,接着遍历下一个页面,将访问位置设置为0,接着遍历下一个页面,当下次遍历到访问位为0,则需要置换

最佳置换算法:是基于未来的访问页面的使用情况,置换最长时间没有访问的页面。但是我们不清楚未来的页面的情况,操作系统也不知道,属于一种理想条件的置换算法,通常无法实现。

select、poll、epoll的区别

I/O多路复用机制是通过select、poll、epoll系统调用完成的。

select是最古老的一种I/O多路复用机制,他可以监视多个文件描述符,可读、可写和错误状态。select效率会随着文件描述符数量的增加而减低效率。

poll是select的一种改进,他采用轮询访问监视多个文件描述符的状态,避免了select文件描述符受限的问题,但是如果存在大量的文件描述符,poll的性能也变不怎么高效。

epoll是Linux下一种特殊的I/O多路复用机制,相较于select和poll,处理大量的文件描述符时更加高效。epoll是通过事件通知的方式,只有当文件描述符准备就绪才会通知应用程序,不需要应用程序轮询

I/O多路复用机制允许了一个线程可以处理多个I/O操作,避免了多个进程和线程的开销。