操作系统
1. 操作系统主要功能
-
进程管理
- 功能:创建、调度、终止进程,管理进程的执行。
- 目的:确保多个进程能够有效地共享处理器资源,并进行合理的调度和管理。
-
内存管理
- 功能:分配和管理系统内存,包括虚拟内存和物理内存。
- 目的:提供程序执行所需的内存空间,并保护进程之间的内存隔离。
-
文件系统管理
- 功能:提供文件的创建、删除、读写及管理文件系统的结构。
- 目的:有效地存储和组织数据,提供对数据的持久访问。
-
设备管理
- 功能:管理和控制输入输出设备,如硬盘、打印机和网络设备。
- 目的:为应用程序和用户提供设备访问接口,协调设备操作。
2. linux的进程管理、内存管理、中断管理、文件管理
-
进程管理:
使用进程控制块(PCB)来管理进程,包括创建fork(exec加载和执行),调度(时间片,从就绪队列中选取一个进程,非抢占,抢占)和终止进程 进程状态:就绪,运行,阻塞,终止 -
内存管理:
为了支持多道程序并发执行。内存空间分配与回收(块,段、页,段页),地址转换(逻辑物理),内存空间扩容(虚拟内存),存储保护 -
中断管理:
处理硬件和软件中断请求,包括中断请求/响应/上下文回复/中断优先级处理/中断屏蔽 -
文件管理:
涉及创建mkdir,touch、读取cat、写入echo、删除文件rm,以及管理文件的属性和权限。采用树形目录结构,使用文件控制块FCB存放控制文件的数据结构。
3. 操作系统的硬中断和软中断
中断是系统响应硬件/软件设备消息的一种机制
-
硬中断
外设产生
由与系统相连的外设(比如网卡、硬盘)自动产生的,主要是用来通知操作系统系统外设状态的变化
-
软中断
中断指令产生
硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断
4. 文件系统
用于组织、管理和存储数据在存储设备上的方式。
文件系统为文件和目录提供一个结构化的存储机制,使得用户和程序能够方便地访问、修改和管理文件。文件、目录、路径、文件控制块。
5. 什么是字符设备、块设备
-
字符设备(Character Device)
是一种以字符流的形式进行数据读写的设备。它们通常支持逐字节或逐字符的操作,不提供随机访问能力,如键盘、显示器)和打印机 -
块设备(Block Device)
是一种以块(通常为固定大小的数据块,如 512 字节或 4 KB)为单位进行数据读写的设备。块设备支持随机访问和顺序访问。硬盘、固态硬盘(SSD)、CD-ROM 和 USB 存储设备
6. 用户态和内核态
用户态只能访问受限的内存,应用程序需要通过系统调用来请求操作系统提供服务。
7. Linux虚拟内存
Linux 虚拟内存是操作系统提供的一种内存管理机制。
它允许应用程序使用比实际物理内存更多的内存,同时提供内存保护和进程隔离。每个进程在运行时拥有独立的虚拟地址空间,不直接对应实际的物理内存。
8. 进程线程比较
- 定义:
-
进程是操作系统中资源分配和调度的基本单位,每个进程都有自己独立的地址空间、内存、文件描述符、堆栈和程序计数器等资源,进程之间资源是隔离的,单核CPU并发执行
-
线程是CPU调度和分配的基本单位,是进程中的一个执行单元,线程间共享进程的地址空间和资源
- 资源:
-
进程拥有自己的独立资源,线程间不能直接访问不同进程的资源,进程间通信(IPC)如管道、消息队列、共享内存等用于实现进程间的数据交换。
-
线程之间的通信更方便,线程共享同一进程的地址空间和资源,但每个线程有自己的堆栈、寄存器和程序计数器。
- 开销:
-
进程的创建和销毁开销较大,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,进程上下文切换比线程上下文切换开销更大,但是能够很好的进行资源管理和保护,可以跨机器迁移。
-
线程的创建和销毁开销较小,因为线程间的资源共享减少了资源分配和管理的复杂性,但是不利于资源的管理和保护。
- 鲁棒性:
-
进程间的隔离提供了较高的鲁棒性,一个进程的崩溃不会直接影响到其他进程。
-
由于线程共享进程的资源,一个线程的崩溃可能会影响到整个进程中的其他线程。
- 适用场景:
-
对资源的管理和保护要求高,不限制开销和效率时,使用多进程,例如运行不同的应用程序。
-
要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程
9. 进程的创建过程
-
为新进程分配一个唯一的进程标识符。
-
为进程分配空间。这包括进程映像中的所有元素。
-
初始化进程控制块。
-
设置正确的链接。例如,若操作系统将每个调度队列都维护为一个链表,则新进程必须放在就绪或就绪/挂起链表中。
-
创建或扩充其他数据结构。
10. 进程有哪些状态
- 运行:进程正在执行。
- 就绪:进程准备好运行,等待 CPU。
- 阻塞:进程等待事件或资源。
11. 进程中的写时拷贝
在有多个进程或线程需要共享同一块数据时,操作系统会允许它们共享同一个数据块的副本,而不是为每个进程分配独立的内存空间。只有当其中一个进程尝试修改数据时,系统才会实际进行数据的拷贝,为该进程创建一个独立的副本
1.初始状态:共享数据
2.检测写操作:触发拷贝
3.独立操作:互不影响
12. 进程上下文、进程切换做的事情
进程上下文(Process Context)指的是一个进程在操作系统中的状态和资源信息,它包括进程执行的当前状态、寄存器内容、内存映射、程序计数器等。
-
保存之前运行的进程上下文
-
调用准备运行的进程的上下文
-
CPU使用权交接
进程上下文:保存CPU寄存器的值,进程状态以及堆栈内容
保存之前运行进程的上下文,这里有几个关键的处理器中的寄存器,一个是PC寄存器,指向当前运行时的进程,一个是PSW,程序状态寄存器,记录计算的记过以及一些控制信息,然后就是处理器的堆栈指针SP(Stack Point)用来记录当前运行进程的PCB控制信息。
在记录被切换的进程上下文时,要将PC寄存器,PSW以及其他相关寄存器的数据存入进程的私有堆栈中,以及SP存入PCB中。
13. 进程调度,调度算法,完全公平调度、优先级设置、非抢占式、抢占式
-
决策模式:
非抢占:一旦进入运行状态,就不会终止直到运行结束。
抢占:当前正在运行的进程可以被打断,并转移到就绪态。
-
FCFC先来先服务调度算法(非抢占)
first come first serve,先来先服务调度算法,即谁先来谁先进行,按照到达顺序依次服务调度
-
SJF短作业优先调度算法(非抢占)
shortest job first,短作业优先调度算法,即先看哪个算法先来,再看谁的服务时间短,服务时间短的那个先服务
-
SRTF最短剩余时间优先调度算法(抢占式)
shortest remaining time first,最短剩余时间优先调度算法,如果新到达的作业剩余时间比当前运行的作业剩余时间更短,则先处理新到达的作业,当前运行进程重新回到就绪队列,准备后续的服务
-
RR时间片轮转调度算法(抢占式)
按照各进程到达就绪队列的顺序,轮流让各个进程执行一个时间片
-
PSA优先级调度算法(抢占式、非抢占式)
根据确定的优先级选取进程/线程,每次总是选择就绪队列中优先级最高者运行
14. 进程通信和线程通信的方式
-
进程通信:
有名管道/无名管道、信号、共享内存、消息队列、信号量、socket
1.消息队列:进程可以向消息队列发送和接收消息,消息按发送顺序存储在队列中。 2.信号:用于通知进程发生了特定的事件。通常用于中断、终止进程或进行进程间的简单通信。 3.信号量:计数器,主要用于进程间的同步,而不是数据交换,用于控制对共享资源的访问,防止竞争条件。 4.管道:适用于简单的父子进程通信,数据流较小。半双工。速度慢,容量有限。 5.共享内存:效率最高,多个进程可以直接访问相同的内存区域。需要同步机制(如信号量)来防止数据竞争。 6.socket:不仅用于本地进程间通信,还可以用于网络进程间通信。支持全双工通信,适合分布式系统。
-
线程通信:
信号量、读写锁、条件变量、互斥锁、自旋锁
自旋锁是一种对临界资源进行互斥访问的手段,获得锁的的任务能对临界进行操作,操作完后解锁,没有获得锁的任务则循环等待锁可用,相当于原地打转自旋
15. mmap的通信过程
1.创建/打开文件
2.映射文件到内存
通过调用mmap系统调用,进程可以将这个文件映射到自己的虚拟内存空间中
3.进程间通信
多个进程可以分别调用mmap,将同一个文件映射到它们各自的内存空间中。由于映射的内存区域是共享的,一个进程对这块内存的修改可以被其他映射了该区域的进程实时看到。数据的读写就像操作普通内存一样,不再需要调用系统的read和write函数,因此通信效率较高。
4.同步和互斥
由于多个进程可能同时访问同一块共享内存,必须使用同步机制(如信号量、互斥锁等)来防止数据竞争或冲突。
5.解除映射和关闭文件删除文件
16. 僵尸进程 孤儿进程 守护进程
-
僵尸进程:已经终止但仍占用系统资源的进程,等待父进程获取其终止状态。
-
原因:在多进程编程中,当子进程结束时,父进程未调用wait()或waitpid()清理子进程的状态,会产生僵尸进程。避免:可以使用signal()设置SIGCHLD信号处理函数,在子进程结束时立即回收资源,以避免僵尸进程。
-
危害:僵尸进程保留的信息不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
-
清理:无法kill,可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。
-
-
孤儿进程:父进程终止后仍在运行的进程,最终由init进程(在系统中PID为1的进程)接管。
-
守护进程:长期运行在后台、独立于终端和用户的进程,通常负责系统服务。
17. 多线程的同步与互斥
线程同步是指在多线程环境下,通过某种机制来控制线程对共享资源的访问,以避免数据不一致或竞态条件的发生,确保多线程程序的正确性和可靠性。
同步用于协调线程的执行顺序和通信,而互斥则用于防止多个线程同时访问共享资源,从而避免数据竞争和不一致性。
互斥机制:
-
互斥锁(Mutex)
互斥锁是用于确保同一时刻只有一个线程可以访问共享资源的一种机制。
线程在访问共享资源前需要先获取互斥锁,访问完成后释放互斥锁。其他线程在锁被占用时会被阻塞,直到锁被释放。
同步机制:
-
读写锁(Read-Write Lock)
读写锁允许多个线程同时读取共享资源,但在有一个线程正在写入资源时,其他线程无法读或写。它适用于读多写少的场景。
-
信号量(Semaphore)
信号量是一种计数器,控制对共享资源的访问次数。它可以允许多个线程同时访问资源,但数量是有限的。
信号量可以用于实现比互斥锁更灵活的同步机制,例如控制一定数量的线程并发执行某些操作。
-
条件变量
条件变量用于线程之间的等待与通知机制。一个线程可以等待某个条件成立,而另一个线程在条件成立时通知它继续执行。条件变量通常与互斥锁配合使用,适用于线程需要等待特定条件的场景。
-
自旋锁
不会导致睡眠的锁机制,采用循环加锁->等待的机制
自旋锁最多只能被一个可执行线程持有,如果一个线程试图获得一个已经被持有的自旋锁,那么该线程将循环等待,然后不断判断锁是否能被成功获取,直到获取到锁才退出循环。
自旋锁是一种对临界资源进行互斥访问的手段,获得锁的的任务能对临界进行操作,操作完后解锁,没有获得锁的任务则循环等待锁可用,相当于原地打转自旋
18. 死锁,怎么解决死锁
定义:死锁是指两个或多个进程在执行过程中,因为竞争资源而造成的一种互相等待的状态,导致所有进程都无法继续执行。
必要条件:互斥、不剥夺、请求并保持、循环等待 (死锁预防:破坏必要条件)
避免死锁:允许进程动态的申请资源,但系统分配之前需计算分配的安全性,银行家算法
使用std::lock等工具来预防死锁
19. 多线程场景下会出现什么问题,怎么解决
1.数据竞争(Race Condition):
问题:多个线程同时访问共享数据,并尝试修改它,可能导致数据不一致或意外行为。
解决方法:使用同步机制如互斥锁(Mutex)、读写锁(Read-Write Lock)或原子操作(Atomic Operation)来确保数据的一致性。
2.死锁(Deadlock):
问题:两个或多个线程相互等待对方释放资源,导致程序无法继续运行。
解决方法:避免循环等待,使用超时锁定(Timed Lock)、分层锁(Lock Ordering)策略,或通过死锁检测机制来解决。
3.活锁(Livelock):
问题:线程不断改变状态以响应对方的状态,但无法推进(比如频繁释放和重新获取锁)。
解决方法:限制重试次数,或通过增加一定的随机等待时间来避免这种情况。
4.资源饥饿(Starvation):
问题:某个线程一直无法获取所需的资源,导致无法执行(例如优先级较低的线程)。
解决方法:使用公平锁(Fair Lock)或线程调度策略(如优先级继承)来保证所有线程都能获得资源。
5.竞态条件(Race Condition):
问题:程序的行为依赖于线程的执行顺序,而这个顺序是不可控的,可能导致意外结果。
解决方法:通过同步措施控制执行顺序,确保在适当的时刻进行数据访问。
总的来说,多线程问题通常通过同步机制(如锁、信号量)、设计模式(如生产者-消费者、读者-写者问题)以及编程规范(如避免共享可变状态)来解决,确保线程安全和资源的合理调度
20. 信号量和互斥锁的应用场景
-
信号量
是一种计数器,允许多个线程或进程访问共享资源。信号量有两种类型:二元信号量(类似于互斥锁)和计数信号量(允许多个线程同时访问资源)。不同于互斥锁,计数信号量可以允许多个线程同时访问共享资源(计数器大于1时)。
适用于多线程访问场景。
-
互斥锁
是一种用于保护共享资源的同步机制,确保同一时间只有一个线程可以访问该资源。它通常用于实现临界区的保护。互斥锁是排他性的,当一个线程锁定了资源,其他线程必须等待该锁被释放后才能访问该资源。
适用于需要独占访问的场景。
21. 单线程下会出现数据不一致问题吗,举例说明
在单线程环境下,虽然不会出现多线程中的数据竞争,但由于异步操作、回调函数或信号处理的干扰,仍然可能引起数据不一致的问题。这些问题通常需要通过增加同步机制或限制干扰源来解决。
-
异步操作导致的数据不一致
异步操作是指不按照主程序的执行顺序,而是会在某个时间点自动触发的操作,比如定时器回调、网络请求的回调等。它们可能在程序执行过程中任意时刻插入,打断当前的执行流并修改数据。
-
信号处理导致的数据不一致
信号处理是操作系统中断程序执行的机制,通常用于处理特定的事件(如Ctrl+C发送的 SIGINT 信号)。当信号被处理时,当前的程序执行被中断,转而执行信号处理函数,这可能会对全局数据造成修改。
解决这些问题的关键在于:
-
控制执行时序:通过屏蔽或延迟异步事件。
-
保护关键区域:确保关键数据的修改不会被外部操作打断。
-
最小化干扰:尽可能减少异步操作或信号处理对全局状态的直接修改。
22. I/O多路复用 select、poll、epoll
多路复用技术用于管理和处理多个 I/O 操作的并发。
-
select:
通过对文件描述符集的轮询来实现程序在一个线程中监视多个文件描述符,从而使得应用程序可以高效地处理多个 I/O 操作。
内核使用数组来存储和管理这些文件描述符的状态。
缺点:文件描述符集的大小有限制,对于大量文件描述符,效率较低。每次调用 select 都需要重新设置文件描述符集,效率较低。
-
poll:
是select的扩展,使用 pollfd 结构体数组(每个 pollfd 结构体包含一个文件描述符和一个事件标志)来监视文件描述符。当poll被调用时,内核会遍历 pollfd 数组,检查每个文件描述符的状态。
文件描述符的状态是通过内核中的链表进行管理。不受文件描述符数量限制,但仍然需要在每次调用时扫描整个数组,不适合大量处理。
-
epoll:
是 Linux 特有的高效的 I/O 事件通知机制,适合处理大量文件描述符。通过内核中的事件表来管理和监视文件描述符。事件表使用如红黑树或哈希表来存储和管理文件描述符及其对应的事件。
23. 如何在Linux中创建、复制、移动、删除文件或目录
- 创建文件:touch filename.txt 或 echo “text” > filename.txt
- 复制文件/目录:cp source destination,使用 -r 选项递归复制目录
- 移动/重命名文件/目录:mv oldname newname
- 删除文件/目录:rm filename 或 rm -r dirname,使用 rmdir 删除空目录
24. Linux找当前目录最大的文件
使用 ls 和 sort 命令(仅限当前目录,不包括子目录)
列出当前目录的文件及其大小,排序并显示最大的文件
25. Linux 中的权限类型,如何修改文件和目录的权限?
- 文件权限:
r
(读)、w
(写)、x
(执行)。 - 目录权限:
r
(列出内容)、w
(创建删除文件)、x
(进入目录)。 - 修改权限:使用
chmod
命令,符号模式或八进制模式。 - 递归修改:使用
-R
选项对目录及其内容进行递归修改。
26. 如何查看系统日志文件,常见的日志系统文件有哪些
在Linux/Unix系统中,系统日志文件通常存储在/var/log目录下,你可以使用文本编辑器(如vim)或者命令行工具来查看日志文件,除了下面两个还有其他的
- /var/log/syslog 或 /var/log/messages:包含了系统启动以来的所有系统日志信息。
- /var/log/auth.log(Ubuntu/Debian)或 /var/log/secure(Red Hat/CentOS):记录了与安全相关的事件,如登录尝试。