嵌入式开发工程师笔试面试指南-操作系统-2
十一 死锁 ⭐⭐⭐⭐⭐
死锁概述
死锁是指两个或多个进程在执行过程中,因竞争系统资源而互相等待对方的资源,导致进程无限期地阻塞的现象。简而言之,就是若干个进程因为相互等待对方释放资源而陷入了死循环,无法向前推进,也无法退出。
死锁通常发生在多个进程共享有限的系统资源时,如共享内存、文件、打印机等。当多个进程都在等待某个资源时,而这些资源又被其他进程占用时,就会出现死锁的情况。例如,进程A占用了资源1,并等待资源2,而进程B占用了资源2,并等待资源1,这样就形成了死锁。
死锁的出现导致系统资源的浪费,也会使得进程卡住,无法完成任务,从而影响系统的稳定性和可靠性。因此,防止和解决死锁问题在操作系统中是一个重要的研究方向。
死锁的起因
造成死锁的起因主要是由于系统资源的竞争和分配不合理,具体来说,有以下几个方面:
- 竞争互斥资源:多个进程竞争同一个互斥资源(比如一块儿共享内存),这种资源只能被一个进程占用,其他进程需要等待资源释放。
- 进程持有部分资源而请求资源:进程已经获得了部分资源,但是又请求其他进程正持有的资源,而这些资源又无法被抢占。
- 进程推进顺序不当引起死锁,除了系统中多个进程对资源的争夺会引起死锁外,进程在运行的过程中,对资源进行申请和释放的顺序是否合法,也是在系统中产生死锁的一个重要因素。
- 资源分配不当:系统在分配资源时出现问题,比如错误的资源分配顺序或者过多地分配资源,从而导致某些进程一直无法获得需要的资源。
- 循环等待:各个进程之间互相等待对方所持有的资源释放,形成了一个循环等待的状态,从而导致了死锁的出现。
因此,为了避免出现死锁,需要合理地设计程序和系统,合理分配资源,并采取一些解决措施,如资源预分配、进程抢占、超时机制和死锁检测和恢复等。
死锁的四个必要条件
死锁是指两个或多个进程在执行过程中,因争夺系统资源而产生的一种僵局,它们都无法继续执行下去。产生死锁的原因在于这些进程相互占用着所需资源却又无法释放,无法向前推进,形成了死结。死锁具有以下四个必要条件:
- 互斥条件:至少有一种资源必须被独占而不能共享,即进程只能拥有一个资源。
- 请求与保持条件:进程必须同时持有所需要的资源并且在等待它未拥有的资源时不释放自己所占有的资源。
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能被其他进程所强制夺去。
- 环路等待条件:由若干个进程之间形成一种头尾相接的循环等待资源的关系,使得请求资源的进程永远不能得到满足。
当以上四个条件全部满足时,就会发生死锁。对于死锁的预防和避免,可以采取一些措施,例如破坏死锁中的其中一个或多个条件等。
预防死锁
预防死锁的方法有以下几种:
1. 避免使用死锁发生的资源:首先避免使用可导致死锁发生的资源,比如互斥锁,限定资源的访问只能单向进行。
- 尽量减少保持资源的时间:在程序中,尽可能减少对共享资源的使用时间,这样可以降低资源竞争的概率,也减小了死锁发生的可能性。
- 破坏循环等待条件:通过规定资源的分配顺序,避免进程之间互相等待。可以采取将所有资源类型编号,要求进程只能按编号升序访问资源的方式,从而避免循环等待的局面。
- 死锁检测和恢复:实时监测系统资源的状态,及时发现死锁,以及采取相应的措施,如释放资源、抢占进程等来解除死锁状态。
综上所述,预防死锁的方法主要是通过限定资源的访问顺序、尽可能减少保持资源的时间、破坏循环等待条件,以及采取死锁检测和恢复等方法,使系统没有死锁的情况出现。
避免死锁
为避免死锁,可以从以下几个方面着手:
- 破坏循环等待条件:通过定义资源使用规则,避免进程之间形成循环等待的情况。
- 预防死锁:避免使用可能导致死锁的资源,尽量减少保持资源的时间,合理分配资源,从而降低死锁的发生概率。
- 死锁检测和恢复:实时监测系统资源的状态,及时发现死锁,以及采取相应的措施,如释放资源、抢占进程等来解除死锁状态。
- 调整资源分配策略:在资源分配策略方面可以尝试采取其他方案,如资源复制、动态资源分配等,进一步减少死锁的概率。
总之,避免死锁需要综合考虑资源分配、进程调度、死锁检测等多方面的因素,并采取相应的措施来确保系统的可靠性和稳定性。具体而言,尽可能地破坏循环等待条件、避免死锁产生、实时检测死锁状态、调整资源分配策略等都是可行的方法。
死锁的检测和解除
死锁的检测和解除死锁的检测和解除是一种重要的死锁处理方法。它的基本思想是通过检测系统的状态并采取相应的措施来解除死锁状态。
在实际应用中,可以采用以下方法来检测和解除死锁:
- 静态检测:通过分析系统的资源分配情况来判断是否会发生死锁。这种方法适用于系统规模较小,资源数量较少的情况。
- 动态检测:在运行时动态地检测系统的资源分配情况,当系统进入死锁状态时,采取相应的措施解除死锁。常用的动态死锁检测算法有银行家算法、死锁检测图算法等。
- 死锁的解除:一旦发现死锁情况,就需要采取相应的措施来解除死锁。常用的死锁解除方法有剥夺资源法、撤销进程法、进程回退法等。
死锁的解除需要仔细考虑,否则可能导致系统的崩溃或丢失数据等严重问题。因此,必须根据具体的情况,综合考虑多种因素,以最小代价解除死锁。
总之,死锁的检测和解除是一种常用的死锁处理方法,主要是通过监测系统状态、判断是否存在死锁并采取相应的解锁措施来保证系统的稳定性和可靠性。
十二 操作系统中的锁 ⭐⭐⭐⭐⭐
临界区
在计算机科学中,临界区(Critical Section,也称作临界段)是指一段代码,这段代码在同一时刻只能被一个进程或线程访问。在临界区内,对于共享的资源(如全局变量、共享内存等)进行操作。因此,在多线程和多进程的环境下,为了避免互相干扰造成资源访问的冲突和数据不一致的情况,需要将临界区的访问进行同步。
当多个线程或进程需要同时访问共享资源时,为了确保数据的正确性,需要使用互斥锁等同步机制来控制线程或进程对临界区的访问。在临界区内,一次只有一个线程或进程能够对共享资源进行读写操作,以避免数据访问的竞争和冲突。
临界区同步机制可以确保任意时刻只有一个线程或进程能够访问共享资源,从而避免了资源争用的问题,并保证了多线程和多进程的环境下程序的正确性和稳定性。同时,合理的使用临界区机制也能够提高程序的运行效率和吞吐量。
需要注意的是,临界区的长度应该尽量的短,只包含必须的代码段,以避免过多的等待锁的时间,造成程序的性能损失。
互斥锁
互斥锁(Mutex)是一种常见的同步机制,用于控制多个线程对共享资源的互斥访问。当一个线程持有互斥锁时,其他线程必须等待该线程释放锁后才能进入临界区。
互斥锁的基本操作包括上锁(lock)和解锁(unlock)。当一个线程要访问共享资源时,它需要先请求(lock)互斥锁,如果互斥锁没有被其他线程占用,则该线程获得锁并进入临界区,否则线程将被阻塞,直到锁被释放为止。当线程完成对共享资源的访问后,它需要调用解锁(unlock)操作来释放互斥锁,以便其他线程可以获取锁并访问共享资源。
互斥锁的优点是敦促线程按照规定的顺序通过临界区,避免了竞态条件和数据竞争,同时提高了程序的可靠性和稳定性。但是,如果互斥锁的使用不当,则可能会导致死锁等问题,因此需要注意锁的使用和释放。
在不同的操作系统和编程语言中,互斥锁的实现方式有所不同。例如,在Linux系统中,可以使用pthread_mutex_t结构体和相关函数来实现互斥锁,而在Java中,可以使用synchronized关键字来实现线程同步和互斥。
读写锁
读写锁(Read-Write Lock)是一种特殊的锁机制。它允许多个线程同时读取一个共享资源,但只允许一个线程写入共享资源。读写锁分为读锁(Shared Lock)和写锁(Exclusive Lock)两种模式。在读模式下,多个线程可以同时持有读锁,而在写模式下,只有一个线程可以持有写锁。
与互斥锁相比,**读写锁的优势在于允许多个线程同时对共享资源进行读取操作,从而提高了并发性能和效率。**在读多写少的场景下,采用读写锁可以更好地利用CPU和资源,避免了读操作的阻塞,提高了程序的响应速度和吞吐量。
但需要注意的是,如果读写锁被频繁的转换成写锁以及持有锁的时间过长,可能会导致锁的竞争和等待时间过长,进而影响程序的运行效率,因此需要在使用读写锁的场景下进行合理的设计和使用。
在Linux系统中,可以使用pthread_rwlock_t结构体和相关函数来实现读写锁,在C++11标准中,标准库提供了std::shared_mutex(共享互斥量)类来实现读写锁。
自旋锁
自旋锁(Spin Lock)是一种特殊的锁机制。不同于互斥锁或读写锁,在自旋锁的实现中,线程不会被挂起或进入睡眠状态,而是在一个循环中不断的尝试去获取锁,直到成功为止。
因为自旋锁不会让线程睡眠或切换上下文,所以它的优点在于减少了线程切换的开销和上下文切换的时间,提高了程序的响应速度和吞吐量。但同时需要注意,如果自旋锁一直无法获取到锁,就会导致线程不停地在循环中忙等待,浪费了CPU的资源。
因此,自旋锁适用于多处理器系统,在这种系统中,对于其他处理器而言,持有锁的线程可能仍然处于就绪状态,因此持有锁的时间很短,使用自旋锁可以减少线程的切换开销以及上下文切换的时间,提高了程序的执行效率。
在Linux系统中,可以使用pthread_spin_lock()函数和pthread_spin_unlock()函数来实现自旋锁。在C++11标准中,标准库提供了std::spin_lock类来实现自旋锁。
条件变量
条件变量(Condition Variable)是一种线程间同步的机制,它允许一个或多个线程在满足特定条件的情况下等待或唤醒其他线程。简单来说,条件变量解决的是线程间的等待和通知问题。
条件变量通常与互斥锁一起使用,因为条件变量最常见的应用场景是在等待共享资源的时候。当一个线程在持有互斥锁的时候,发现所需的共享资源没有准备好,这时就可以使用条件变量将该线程加入等待队列,释放锁并挂起等待条件满足的状态。当其他线程释放资源并通知条件变量后,该线程就可以从等待队列中被唤醒,重新获取互斥锁,继续执行操作。
在Linux系统中,可以使用pthread_cond_t结构体和相关函数来实现条件变量,常用的函数包括pthread_cond_init()、pthread_cond_wait()、pthread_cond_signal()和pthread_cond_broadcast()等。在C++11标准中,标准库提供了std::condition_variable类来实现条件变量。
信号量
信号量(Semaphore)是一种用于进程之间或者线程之间同步的机制。它可以确保在同一时刻内只有一个线程或进程访问共享资源,避免了数据争用和相互干扰。
信号量分为两种类型:二元信号量和计数信号量。二元信号量的取值只有0和1两种,通常用于实现互斥锁的功能,也称为互斥量(Mutex)。而计数信号量的取值可以是任意正整数,它可以用于实现线程的同步和协调操作。
在Linux系统中,可以使用sem_t结构体和相关函数来实现信号量,常用的函数包括sem_init()、sem_wait()、sem_post()和sem_destroy()等。在C++11标准中,标准库也提供了std::counting_semaphore和std::binary_semaphore类来实现计数信号量和二元信号量。
互斥锁、读写锁、自旋锁、条件变量、信号量的区别和各自应用场景
互斥锁、读写锁、自旋锁、条件变量和信号量都是操作系统中常用的同步机制,它们各有不同的应用场景。
- 互斥锁
互斥锁可以确保同一时刻只有一个线程或进程访问共享资源,防止并发访问导致的数据竞争问题,常用于保护共享变量、全局数据和文件等关键资源的访问。适用于互斥资源访问的场景。
- 读写锁
读写锁适用于经常被读取而很少被修改的共享资源,它允许多个线程同时读取资源,但只有一个线程能写入资源。读写锁的引入可以大大提高并发访问的效率,有效降低读取操作的等待时间。适用于读多写少的数据结构和高并发读取的场景。
- 自旋锁
自旋锁也是一种互斥锁,但它采用占用式的轮询方式,而不是将线程阻塞休眠。当发现自旋锁已经被占用时,线程会不断地尝试获取锁,直到获取到为止,从而避免线程上下文的切换和进程间调度的开销。适用于锁的竞争不激烈或者锁的占用时间非常短的场景。
- 条件变量
条件变量通常与互斥锁一起使用,用于线程之间的等待和通知。当一个线程持有互斥锁时,发现所需的条件未满足时,就可以使用条件变量将该线程挂起等待条件满足的状态。当其他线程释放资源并通知条件变量后,该线程就可以从等待队列中被唤醒,重新获取互斥锁,继续执行操作。适用于需要等待条件满足才能进行后续操作的场景。
- 信号量
信号量分为二元信号量和计数信号量。二元信号量通常用于实现互斥锁,它只有两个取值,可以保证在同一时刻内只有一个线程或进程访问共享资源。计数信号量的取值可以是任意正整数,它常常用于实现多个线程之间的同步和协调操作。适用于需要实现进程或线程同步的场景。
综上所述,不同的同步机制适用于不同的应用场景,需要根据实际情况选择合适的同步机制来实现线程间的同步和协作操作。
自旋锁和信号量可以睡眠嘛?为什么?
自旋锁和信号量都是操作系统中的同步机制,不同之处在于它们的策略不同。自旋锁是一种忙等待的策略,即线程会不断地检查锁是否可以被获得。如果锁已经被占用了,线程就会一直占用CPU直到锁被释放。而信号量则是一种休眠的策略,即线程在不能获得资源时会进入睡眠状态,等待其他线程释放资源后,再唤醒自己。
因此,自旋锁是不会睡眠的,它会一直占用CPU,等待锁被释放。这种忙等待的方式会浪费CPU时间,而且由于自旋锁不能睡眠,它在多核处理器上的效率可能比较低。
信号量则是可以睡眠的,因为它采用休眠等待的方式,即当一个线程等待信号量时,它会进入睡眠状态,等待其他线程释放资源后,再被唤醒执行。这种方式可以使得线程占用的CPU时间更少,而且能够提高系统的整体效率。但是仍然需要谨慎使用,因为睡眠和唤醒都需要一定的时间开销,如果频繁的睡眠和唤醒可能会影响系统的性能表现。
总之,自旋锁是一种适用于短时间并发操作的同步机制,而信号量则适用于需要较长时间等待资源的同步场景。在实际应用中,需要根据具体的场景和需求选择合适的同步机制来确保程序的正确性和性能。
自旋锁和信号量可以用于中断嘛?为什么?
在中断处理程序中,一般不应该使用自旋锁和信号量。这是因为中断处理程序必须尽可能快速地完成任务,保证中断的处理能够及时地响应,如果在中断处理程序中使用了自旋锁或信号量,可能会导致以下问题:
- 自旋锁会占用CPU,并且在中断处理程序的上下文中,如果持有自旋锁、则无法响应其他中断,这样会影响系统的实时性,但可以用于中断。由于自旋锁会不断的占用CPU时间,还会增加中断延迟,从而影响系统整体的性能。
- 信号量在等待时会进行睡眠操作,在中断环境中是不能睡眠的,因为中断处理程序是处理异步事件的,中断程序不可被阻塞,否则会引起系统崩溃。
因此,在中断处理程序中,应该避免使用需要等待的同步机制(如信号量、读写锁等),而是应该采用可重入锁或者原子操作等非阻塞的同步机制。这能够使中断处理程序快速地响应和完成处理任务,确保系统实时性和稳定性。
十三 存储管理 ⭐⭐⭐⭐⭐
存储器的层次结构
计算机的存储器层次结构,从下到上依次为:
- 寄存器:位于CPU内部的存储器,速度最快,容量最小,一般只存储少量临时数据和指令操作码。
- 高速缓存(Cache):位于CPU和主存之间的存储器,作为缓存来提供更快的访问速度和更高的访问效率,一般分为L1、L2、L3级别。
- 主存储器(Main Memory):由DRAM(Dynamic Random Access Memory)芯片组成的存储器,是计算机系统中存储数据的主要设备,速度比较快,但容量一般较小。
- 辅助存储器(Auxiliary Storage):例如硬盘、光盘等,容量很大、速度较慢而且访问时间不固定,主要用来长期存储和备份数据,可作为虚拟内存,供程序使用。
以下是存储器层次结构的图示:
--------------------------- | CPU | --------------------------- | --------------------------- | Cache | --------------------------- | --------------------------- | Main Memory | --------------------------- | --------------------------- | Auxiliary Storage | ---------------------------
其中,CPU内部的寄存器与Cache的关系最近,Cache与主存之间的关系其次,主存与辅助存储器之间的关系最远。在程序进行读写操作时,从辅助存储器到CPU的路径上逐级访问,随着存储器层次的提高,存储器的存储速度逐渐提高,但是容量逐渐降低。
这些存储器的速度和容量随层次的不同,从上至下逐渐降低而容量逐渐增大,每级存储器的价格也会随着降低。优化程序在性能上应该利用好高速缓存和主存储器,在程序设计时尽量减少对辅助存储器的访问次数。
程序的装入和链接
程序的装入
定义:是将可执行程序从外存调入内存的过程。程序的装入通常包括以下几个步骤:
- 分配内存空间。操作系统需要查看可执行程序的大小,预留足够的内存空间。
- 加载可执行代码。将可执行程序的二进制代码从外存读入内存中。
- 加载数据段。将可执行程序中的数据段加载到内存中,通常是动态分配内存空间,将数据段内容复制到动态分配的内存空间中。
- 重定位。在加载代码时,需要进行地址的重定位,将程序中使用的地址映射到正确的内存地址上,保证程序能够正确运行。
通常,操作系统会在程序运行启动时,预先分配一段内存用于存储可执行程序,该段内存称为进程空间。进程空间通常包括代码段、数据段、堆和栈等不同区域。可执行代码存储在代码段中,在代码段加载时,需要根据程序代码的起始地址和长度信息计算出代码段中具体的内存地址,并将代码全部加载到指定的内存地址中。
数据段通常存储程序的全局变量和静态变量等数据,由于数据大小可能不确定,因此数据段通常采用动态分配内存的方式进行加载。
在程序加载时,通常需要进行地址的重定位。在编写程序时,通常使用的是逻辑地址,即程序所使用的内存地址是虚拟的,需要在加载时转换成物理地址。由于程序加载位置可能不确定,因此需要将所有的逻辑地址都加上偏移量,计算得到正确的物理地址。
以上就是程序装入的基本步骤。
程序的链接
程序的链接是指将程序的各个模块之间相互调用的关系建立起来的过程,通常包括以下几个步骤:
- 符号解析。将各个模块中的符号引用找到对应的符号定义。
- 地址重定位。将引用的符号的地址映射到正确的地址上。
- 符号决议。将静态链接的符号连接到代码中。
- 重定义。将符号定义合并。
链接可以分为静态链接和动态链接。
静态链接是指将外部模块代码的副本直接拷贝到可执行文件中,使得可执行文件直接包含外部模块中的代码。这种方法使得可执行文件无需依赖外部模块的存在,也不需要在程序运行的时候进行链接。但是,这样会增加可执行文件的体积,使得可执行文件变得更大。
动态链接是指在程序运行时才进行链接,使得程序在链接的时候可以动态地使用外部模块。这种方式使得多个程序可以共享同一个库文件,并且在运行过程中能够动态地升级和替换库文件。但是,动态链接可能会降低程序的执行效率。
分配存储管理方式
存储管理是操作系统中非常重要的一个功能。它的主要任务是对计算机的物理内存进行分配和管理,以便让不同的程序和进程能够共享计算机的内存资源。常见的存储管理方式包括以下几种:
- 单一连续分配:将整个内存分配给一个进程使用,操作系统只有在进程执行完毕后才能释放内存。这种方式适用于单用户系统,但不适用于多任务操作系统。
- 固定分区分配:将内存划分成多个固定大小的区域,每个区域只能分配给一个进程使用。这种方式比较简单,但是容易浪费内存空间。
- 动态分区分配:将内存分成不同大小的块,每个进程请求分配内存时,会从可用的块中选择一个大小适合的块进行分配。这种方式比较灵活,但是需要维护一个内存管理表,而且容易产生内存碎片问题。
- 伙伴系统:将内存分成大小相等的块,每次分配内存时,选择一个大小刚好的块进行分配,如果需要更大的内存时,则从相邻的两个较小块中合并成一个相对较大的块。这种方式相比于动态分区分配效率更高,但是实现相对较为复杂。
- 虚拟存储:在实际内存不足时,将部分不常用的数据和代码转移到硬盘等外部存储器中,以释放内存空间。由于硬盘速度较慢,虚拟存储的性能相比于实际内存较低,但是可以大大扩展计算机的内存容量。
动态分区分配算法
动态分区分配是一种可以动态地为进程分配内存的方式,根据进程的需要,将内存分成多个不同大小的块。当进程需要内存时,动态分区分配算法会按照一定规则从内存块中选取一个大小适合的块分配给进程。主要的动态分区分配算法包括以下几种:
- 首次适应算法(First Fit):分配时从内存分区的起始地址开始查找,找到第一个能满足需求的分区进行分配。由于查找速度快,所以操作效率较高,但是可能会产生较多的内存碎片。
- 最佳适应算法(Best Fit):分配时从内存分区中找到能满足需求且大小最小的分区进行分配。这种方式可以更充分地利用内存空间,但是搜索代价较大,容易产生大量的未分配空间。
- 最坏适应算法(Worst Fit):分配时从内存分区中找到能满足需求且大小最大的分区进行分配。与最佳适应算法相比,最坏适应算法更容易产生较大的未分配空间。
- 循环首次适应算法(Next Fit):与首次适应算法类似,但是从上次分配分区的下一个开始搜索,避免了每次都从头开始搜索的开销,减少了碎片产生的概率。
这些算法各有优缺点,根据实际需求选择合适的算法。
分页存储管理方式
分页存储管理方式是一种内存分配方式,将物理内存分成大小相等的若干个固定大小的块,称为页框(Page Frame)。同时,将进程的虚拟地址空间分成大小相等的若干个固定大小的块,称为页面(Page)。当进程需要使用某个页面时,操作系统将其映射到某个页框中,页框的大小通常为 4KB 或 8KB。
此外,分页存储管理方式需要使用页表(Page Table)进行虚拟地址到物理地址的转换。页表是一个记录了所有页面与页框之间映射关系的数据结构,每个进程都有自己独立的页表。当进程访问某个页面时,操作系统会根据页表将该页面映射到对应的物理地址上。
分页存储管理方式的优点是:
- 提高了内存利用率:按照固定大小划分内存空间,避免了内存碎片的产生,提高了内存利用率。
- 方便了进程的内存管理:通过使用页表实现虚实地址的映射,进程可以更方便地进行内存管理。
- 提高了系统的可靠性:通过使用分页机制,使得操作系统能够更方便地对内存空间进行保护和管理,提高了系统的可靠性。
但分页存储管理方式也存在一些缺点:
- 由于每个进程都需要有一份页表,并且页表较大,需要额外的内存空间,因此会增加操作系统的开销。
- 分页会导致一些额外的开销,如页表的查询和更新、页面的拷贝等,这些操作都会导致一定的开销。
分段存储管理方式
分段存储管理方式是一种将进程的虚拟内存空间划分为多个大小不同的段,每个段代表着不同的逻辑单元,如代码段、数据段、堆栈段等。与分页方式类似,每个段都被映射到物理内存中的某个区域。
分段存储管理方式的优点:
- 每个段都有特定的逻辑含义,使得程序的分析和设计更为方便。
- 每个段的大小可以根据其需要进行动态分配,可以更精确地控制内存的使用。
- 避免了由内部碎片带来的浪费。
- 同一段内的地址空间可以连续使用,便于内存的管理和维护。
分段存储管理方式的缺点:
- 由于每个进程的段数及大小都不同,因此需要使用表格来存储段信息,会增加表格的复杂程度。
- 分段模式中,段与段之间不是必须紧密相邻的,并且可能会发生随机存取,这样就会造成重复而频繁的内存空间的调用和切换,这样会拖累整个系统的速度。
- 由于段的大小不同,因此碎片问题仍然存在,如果不加以管理,会浪费部分内存空间。
总的来说,分段存储管理方式的优缺点与分页相比,二者都有其适用的场景。分页更适合于进程内存的紧凑管理,而分段更适合于程序中多个逻辑单元的分离存储。
段页式存储管理方式
段页式存储管理方式是将段式存储管理方式和页式存储管理方式结合起来的一种存储管理方式。它将进程的虚拟地址空间划分为多个段,然后将每个段再划分为多个页面。
段页式存储管理方式的优点:
- 可以兼具段式存储管理方式和页式存储管理方式的优点,既能够体现程序的逻辑结构,又能够提高内存利用率。
- 分页可以减小内存碎片,有效提高了内存的使用率。
- 不同的段可以分别采用不同的分页方式,用于不同的内存管理需求,灵活性更高。
- 可以避免页式存储管理方式由于过多的交换页面导致的性能下降问题。
段页式存储管理方式的缺点:
- 管理复杂度高,需要维护多级页表和多级段表,增加了内存访问的开销。
- 物理内存分配过小,可能会导致分配不足的问题,这需要系统支持动态内存分配。
- 段与段之间的地址空间可能不连续,需要额外的机制来处理段与段之间的访问。
总的来说,段页式存储管理方式是在分段和分页的基础上结合起来的一种存储管理方式,既具有段式存储方式的管理优点,又避免了页式存储管理方式的管理缺陷。但是由于其管理复杂度高,因此需要在实际应用中进行权衡和选择。
十四 虚拟存储器 ⭐⭐⭐⭐⭐
虚拟存储器概述
虚拟存储器(Virtual Memory)是一种计算机内存管理技术,它使得计算机可以同时运行多个大型应用程序,并将内存中正在使用的部分数据暂时存储到磁盘,从而释放出更多的内存。
虚拟存储器的基本原理是将内存空间分为一组固定大小的块(称为页面或页),当内存不足时,可将当前未被使用的页面从内存中存储到磁盘的虚拟存储器中。当程序需要这些页面时,系统可以将它们读回到内存中。
虚拟存储器技术可以提高计算机系统的性能和可用性,具有以下优点:
- 能够运行更多的程序,提高系统的并发性能和效率。
- 易于管理和分配内存,不需要手动控制内存分配和释放。
- 能够充分利用系统的物理内存和磁盘空间,避免了因内存不足而导致的程序运行错误或奔溃问题。
- 能够限制程序对物理内存的依赖,提高系统的稳定性和可靠性。
虚拟存储器技术的实现需要硬件和软件的支持,例如内存管理单元(MMU)、虚拟地址转换、页面置换算法等。虚拟存储器技术也存在一些缺点,如性能开销、磁盘空间占用和页面置换算法带来的开销等。
虚拟存储器定义和特征
虚拟存储器(Virtual Memory)是计算机内存管理技术的一种。它将磁盘作为扩展的内存空间,通过将物理内存中的部分数据和指令暂时交换/移动到磁盘中,以释放物理内存的空间供其他进程或程序使用。因此,虚拟存储器是一个计算机系统虚拟内存模型,使得计算机上运行的程序可以操作比物理内存更大的地址空间。
虚拟存储器的特征如下:
- 虚拟内存的大小可以比物理内存大。虚拟内存通常是通过将物理内存和存储在磁盘上的虚拟内存页面组合而得到的。
- 虚拟内存页面的大小通常是固定的。通常使用大小为4KB或8KB的虚拟页面大小。
- 虚拟存储器的访问时间比物理内存的访问时间要慢。这是因为当程序访问虚拟内存时,它必须经过磁盘和总线等慢速设备,而物理内存直接与CPU相连,访问速度更快。
- 虚拟存储器必须进行页面置换(Page Replacement)算法来保持虚拟内存与物理内存的一致性。当内存不足时,操作系统会将一部分物理内存页面移动到磁盘上,然后把所需的虚拟内存页面载入到物理内存中。
- 虚拟内存页面的读取和写入需要借助Page Fault(页故障)的机制进行。当一个程序试图访问不存在于物理内存中的虚拟页面时,CPU将会产生一个中断,操作系统会响应这个中断请求并将所需的虚拟页面读入内存,然后再向CPU返回数据。\
总的来说,虚拟存储器是一个能够允许程序在虚拟地址上访问更多内存的技术,其基本原理是允许操作系统将运行程序所需的内存数据和指令交换到磁盘上,从而使得计算机系统能够同时运行多个大型应用程序。虚拟存储器需要使用复杂的算法和管理机制来保持物理内存和虚拟内存之间的一致性,并且也存在着一些缺陷和性能瓶颈。
虚拟存储器的实现方法
实现虚拟存储器需要解决两个主要问题:分页(Page)和页面置换(Page Replacement)。
分页是指将进程的虚拟地址空间划分成固定大小(一般为4KB)的块,称为虚拟页面(Virtual Page),并将虚拟页面映射到物理内存中的实际页面(Physical Page)。这个映射关系可以通过页表(Page Table)来记录和管理。
页面置换是指在物理内存不足的情况下,操作系统需要将一些已经在物理内存中的页面置换到磁盘上,在此过程中,需要解决页面置换策略的问题。
常用的虚拟存储器实现方法包括以下几种:
- 基于分页的虚拟存储器系统,也称为分页式虚拟存储器(Paged Virtual Memory)。此种方式下,进程地址空间被划分成与物理内存大小相等的虚拟页面,每个虚拟页面会被映射到对应的物理页面。不足之处是,当发生页面置换时,一般是将整个页面写回到磁盘,代价较大。
- 基于分段的虚拟存储器系统,也称为分段式虚拟存储器。这种方式下,进程地址空间被划分成许多逻辑段,每段大小不一,并通过页表映射到物理内存中。在发生页面置换时,只需将不包括进程代码的数据段的内容写回到磁盘即可。
- 段页式虚拟存储器系统是分页和分段的结合,它可以兼顾两者的优点,数据段可以按页的方式管理,而代码段可以按分段的方式管理。
无论使用哪种实现方式,虚拟存储器的核心目标都是将物理内存与虚拟内存快速地映射,并且要能够检测到物理内存的使用情况,以进行页面的置换和数据的交换,从而实现多任务操作系统处理更多任务的目标。
请求分页存储管理方式
分页存储管理方式是一种将进程地址空间分割成等大小的页面,每个页面映射到物理内存的方式。具体实现中,操作系统会在内存中建立一个页表(Page Table),页表中记录了每个页面的映射情况,包括虚拟页面号(Virtual Page Number,VPN)和物理页面号(Physical Page Number,PPN)等信息。当进程需要访问某个虚拟页面时,硬件将使用页表进行地址转换,将虚拟地址转换为物理地址。
在分页存储管理方式下,同时也需要在硬件中添加一个页表基址寄存器(Page Table Base Register,PTBR),用于存储页表的起始地址。此外,由于进程地址空间可能比物理内存大,因此可能出现某个页面在内存中没有空闲物理页面可以映射的情况,此时需要进行页面置换(Page Replacement)。常用的页面置换算法包括 FIFO(First In First Out)、LRU(Least Recently Used)等。
分页存储管理方式的优点在于实现简单、页大小固定等,它的缺点则在于有一定的内存浪费(可能存在部分页面只使用了一小部分),同时由于分页机制带来了比较大的开销,因此可能影响计算机系统的性能。
页面置换算法
页面置换算法是指当一个页面需要调入内存,而内存中没有足够的空闲物理页面可供使用时,需要从内存中选择一个页面进行置换(即移出内存),以腾出空间存放新的页面。目前常用的页面置换算法包括如下几种:
- FIFO(First In First Out)算法:选择最早进入内存的页面进行置换。
- LRU(Least Recently Used)算法:选择最近最久未使用的页面进行置换。
- OPT(Optimal)算法:选择未来最长时间内不会被访问的页面进行置换。
- CLOCK(时钟)算法:将所有页面组织成一个环形链表,每个页面都有一个“访问位”(在时钟算法中也称为“引用位”或“请求位”),当页面首次进入内存时,该位被设置为1,每次访问该页面时,该位被更新为1。当需要置换页面时,从环形链表当前位置开始,选择第一个访问位为0的页面进行置换,同时更新当前位置。
以上算法各自有各自的优缺点。FIFO算法实现简单,但其缺点是不能区分不同页面的访问频次;LRU算法能够更好地反映页面使用情况,但需要维护一个较为复杂的数据结构,可能会降低系统性能;OPT算法理论上是最优的,但无法实现;CLOCK算法能够反映时间局部性,且实现简单,但会出现页面闪回(即页面频繁被置换进出内存)的问题。在实际应用中,需要根据具体情况综合考虑选择适合的页面置换算法。
产生抖动的原因?如何预防抖动?
抖动是指系统频繁地进行页面置换,导致系统响应迟缓,甚至出现卡顿现象。产生抖动的原因主要有两个:
- 内存不足:如果系统中的活动集超过了可用内存的大小,就会频繁地进行页面置换,导致系统产生抖动。
- 进程间资源竞争:如果多个进程同时竞争资源,如共享内存,就会导致互相抢夺资源,从而出现页面频繁置换的情况。
要预防抖动,需要采取以下措施:
- 增加内存:如果系统中的活动集超过了可用内存的大小,那么增加内存是最有效的预防措施之一。
- 调整虚拟内存设置:根据实际需要调整虚拟内存的大小和参数设置,以确保系统正常运行。
- 优化进程管理:对于多进程系统,在进程间共享资源时,需要采取适当的竞争机制,以避免资源竞争,从而降低页面置换的频率。
- 采用合适的页面置换算法:在实际应用中,需要选择合适的页面置换算法,从而减少页面置换的频率,降低系统抖动的风险。
请求分段存储管理方式
分段存储管理方式是指将进程地址空间分成若干个段,每个段可用于存储某种类型的数据(如代码段、数据段、堆栈段等),并对不同段进行独立的管理。
在分段存储管理方式中,每个段都有自己的起始地址和长度,以及权限信息(如读、写和执行等),并且段之间没有严格的地址连续性关系。在进行地址转换时,需要使用段表来记录每个段的信息,并根据段表进行对应的地址映射。
与分页存储管理方式相比,分段存储管理方式更适用于需要动态分配内存的应用场景。例如,当进程需要动态创建一个新的数据段或堆栈段时,可以通过分段管理方式比较方便地实现。
在实际应用中,分段存储管理方式具有一定的优点和缺点。其中,优点包括:
- 适用于动态分配内存的场景,方便灵活。
- 不同段之间进行独立管理,有利于提高系统的安全性和可靠性。
- 有效地解决了不同进程地址空间之间相互干扰的问题。
缺点包括:
- 段的长度不易确定,可能会导致内存碎片,影响系统性能。
- 地址转换与页表相比需要消耗更多的时间和资源。
总的来说,分段存储管理方式是一种比较实用和灵活的存储管理方式,在需要动态分配内存的场景下比较适用。
什么是页表,为什么要有?
页表是虚拟内存的概念。操作系统虚拟内存到物理内存的映射表,就被称为页表。
原因:不可能每一个虚拟内存的 Byte 都对应到物理内存的地址。这张表将大得真正的物理地址也放不下,于是操作系统引入了页(Page)的概念。进行分页,这样可以减小虚拟内存页对应物理内存页的映射表大小。(举个例子,就如同一本书,我们如果全展开,那占地面积就大了,所以我们要分页)
简述操作系统中的缺页中断
缺页异常:malloc和mmap函数在分配内存时只是建立了进程虚拟地址空间,并没有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的虚拟内存时,处理器自动触发一个缺页异常,引发缺页中断。
缺页中断:缺页异常后将产生一个缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。
虚拟地址到物理地址怎么映射的?
操作系统为每一个进程维护了一个从虚拟地址到物理地址的映射关系的数据结构,叫页表。页表的内容就是该进程的虚拟地址到物理地址的一个映射。页表中的每一项都记录了这个页的基地址。
三级页表转换方法:(两步)
(1)逻辑地址转线性地址:段起始地址+段内偏移地址=线性地址
(2)线性地址转物理地址:
每一个32位的线性地址被划分为三部分:页目录索引(10位)、页表索引(10位)、页内偏移(12位)
从cr3中取出进程的页目录地址(操作系统调用进程时,这个地址被装入寄存器中)
页目录地址 + 页目录索引 = 页表地址
页表地址 + 页表索引 = 页地址
页地址 + 页内偏移 = 物理地址
十四 输入输出系统 ⭐⭐⭐⭐⭐
输入输出系统基本功能
输入输出(简称I/O)系统是计算机系统中非常重要的一个部分,主要负责连接计算机和外设之间的数据传输。
I/O系统的基本功能如下:
1. 设备管理:I/O系统需要与硬件设备进行交互,监听设备请求和响应,控制设备的操作,以及对不同设备进行管理。
- 缓存管理:I/O系统需要从外设读取数据,并将其复制到内存中以供其他系统使用。因此,I/O系统需要具备缓存管理能力,以管理内存中存储的数据并提高数据访问效率。
- 错误处理:I/O系统需要对不同的输入输出错误进行处理,例如设备故障、数据传输错误等等。对于这些情况,I/O系统需要进行相应的错误处理,并将错误信息反馈给其他部分。
- 中断处理:当外设传输数据时,I/O系统需要不间断地与设备进行通信。在此过程中,如有需要,设备会向I/O系统发送中断请求。I/O系统需要及时响应中断请求,并执行相应的操作。
- 设备驱动程序:I/O系统需要与设备驱动程序进行交互,以实现硬件和软件之间的协作。设备驱动程序是一种软件程序,能够帮助操作系统与硬件设备进行通信。
综上所述,I/O系统是一个非常重要的部分,它承担了数据传输与处理的重要职责。通过合理地管理设备和数据,以及对错误、中断和驱动程序进行处理,I/O系统能够提高计算机系统的可靠性和性能。
输入输出系统层次结构和模型
输入输出(I/O)系统是计算机系统的重要组成部分,它主要负责计算机与外部设备之间的数据传输和管理。I/O系统的层次结构包括以下五个层次:
- 用户层:用户层是最上层的I/O接口,它提供了与应用程序交互的用户接口。用户层的作用是将操作系统层的I/O操作封装成更高层次的操作接口,便于应用程序的调用和使用。
- 设备独立层(DDI):设备独立层是在操作系统和设备驱动程序之间添加的中间层,它主要负责处理设备无关的I/O请求。DDI层允许驱动程序与操作系统进行交互,同时保证了应用程序对设备的访问不受底层硬件设备的限制。
- 驱动程序层:驱动程序层是操作系统和硬件设备之间的接口层。驱动程序层为不同的硬件设备编写了特定的驱动程序,以便操作系统能够识别和管理这些设备。驱动程序还负责在硬件设备和I/O系统之间进行数据传输和管理。
- 控制器层:控制器层是硬件和驱动程序之间的接口层。控制器层是硬件设备的实际接口,它能够与驱动程序交互,并通过驱动程序将数据发送给操作系统。控制器层还能够读取来自操作系统的命令,以便响应不同的I/O请求。
- 设备层:设备层是硬件设备的最底层,它将操作系统的I/O请求转换成实际的数据传输指令。设备层将数据传输给内存或外部设备,以便在计算机系统中进行处理。
I/O系统的模型包括以下几种:
- 块I/O模型:块I/O模型将数据分块传输,它的特点是数据传输量大、传输速度较快。
- 字符I/O模型:字符I/O模型将数据一次一个字符地传输,它的特点是数据传输量小、传输速度较慢。
- 管道/消息模型:管道/消息模型是一种流式I/O模型,通过管道传输数据。它的特点是数据传输与处理的同步性较强,但是由于数据处理需要等待数据传输的完成,导致传输速度较慢。
- 同步I/O模型:同步I/O模型是一种数据传输和请求处理一一对应的I/O模型。它的特点是传输完整数据后,再进行数据处理。同步I/O模型适用于需要对数据进行完整性验证的场景。
- 异步I/O模型:异步I/O模型是一种请求提交和数据传输处理完成异步进行的I/O模型。它的特点是在数据传输过程中,可以同时进行数据处理,提高了I/O的效率和吞吐量。
中断和异常
中断和异常是计算机系统中两种重要的事件机制,它们都是在 CPU 执行程序时发生的,但具体发生的时间和原因不同。
中断是一种异步事件,其发生原因通常是来自外部设备或者操作系统软件的请求。当一个硬件设备收到需要 CPU 处理的事件,例如某个设备的 I/O 操作完成或者出现了设备错误等情况,设备就会向 CPU 发送一个中断信号。当 CPU 接收到中断信号后,它立即停止正在执行的程序,保存当前的程序执行现场,然后转去执行与中断事件相应的中断处理程序。处理程序执行完成后,CPU 恢复之前的执行现场,并继续执行被暂停的程序。总之,中断是在 CPU 执行程序期间,由外部设备或者操作系统软件发起的请求,它会中断当前程序的执行,并转去执行相应的中断处理程序。
异常,也被称为陷阱或者故障,是一种已知的内部事件或错误。异常通常是由 CPU 发现的,其中一些异常是由程序出现错误或者异常操作导致的,例如除以零、越界访问等情况。而另一些异常则由操作系统明确的请求触发,例如进程被非法地访问、空闲任务调用等情况。当 CPU 检测到异常时,它会立即停止当前程序的执行,保存执行现场,并跳转到异常处理程序中。异常处理程序通常会修复该异常并恢复程序的执行,或者出现错误时直接终止程序的执行。
总之,中断和异常都是计算机系统中重要的事件机制,它们有助于解决硬件设备的外部请求和程序内部错误出现的问题,保证了计算机系统的稳定性和可靠性。
中断处理程序
中断处理程序是用于处理中断事件的程序。当 CPU 接收到中断请求信号时,会自动跳转到相应的中断处理程序,进行中断处理。中断处理程序主要包括以下几个步骤:
- 中断响应阶段
CPU 接收到中断请求信号后,会将中断请求标志位设置为 1,以表示中断事件已经发生。此时,CPU 会暂停正在执行的任务,保护现场,保存当前程序计数器、寄存器等信息,然后跳转到中断向量表(Interrupt Vector Table,IVT)中相应的入口地址(也称为中断服务例程地址),开始执行中断处理程序。
- 中断处理阶段
中断处理程序开始执行,它的主要任务是处理中断事件。在中断处理期间,程序需要访问全局变量、数据结构等,因此需要注意程序的可重入性。中断处理程序要尽可能快的完成中断处理操作,并保证中断不被阻塞。
- 中断结束阶段
中断处理程序完成中断处理操作后,需要清除中断请求标志和中断控制器的相应寄存器。然后将保存在栈中的现场信息恢复回来,包括程序计数器、寄存器等。最后,CPU 会继续执行先前被暂停的任务,恢复正常的程序运行。
总之,中断处理程序是处理中断事件的重要程序。在 CPU 接收到中断信号后,会自动跳转到中断服务例程中进行中断处理。中断处理程序需要完成中断响应、中断处理和中断结束等阶段,保证中断处理的正确性和高效性。
设备驱动程序
设备驱动程序是操作系统中的一种软件程序,用于控制设备的访问和管理。设备驱动程序实现了操作系统与硬件设备之间的接口,负责管理输入/输出设备、网络设备、存储设备等硬件设备的访问和操作。
设备驱动程序具有以下几个主要功能:
- 提供设备访问接口:设备驱动程序将硬件设备抽象为一个逻辑设备,并提供相应的访问接口,如打开、关闭、读、写等接口。应用程序通过这些接口来访问和操作硬件设备。
- 管理设备状态:设备驱动程序要实时监测设备的工作状态,维护设备的状态信息,并对设备进行控制和调度。当需要进行故障排除或调试时,设备驱动程序也要提供相应的接口。
- 实现设备的数据传输:设备驱动程序需要对数据进行缓冲的管理和维护,确保数据能够正常传输。当设备出现问题或数据传输不稳定时,设备驱动程序要进行处理和报告错误。
- 管理设备的电源管理:设备驱动程序负责控制设备的电源开关,当设备不在使用时,可以将其关闭以节省能源。
总之,设备驱动程序是操作系统中用于管理和控制硬件设备的重要软件。其主要功能是提供设备访问接口、管理设备状态、实现设备数据传输和管理设备的电源管理。 设备驱动程序的好坏将直接影响到硬件设备的稳定性和整个系统的性能表现。
对I/O设备的控制方式
在操作系统中,I/O设备有三种控制方式,分别是程序控制方式、中断控制方式和直接存储器访问(DMA)方式。
- 程序控制方式:程序控制方式是最常用的I/O设备控制方式。在此方式下,CPU负责I/O操作的所有工作,CPU向I/O设备发送指令、等待I/O设备的数据响应,并将数据传输到内存中。程序控制方式的缺点是会浪费CPU的大量时间来等待I/O操作完成,效率较低。
- 中断控制方式:中断控制方式是一种更高效的I/O设备控制方式。在此方式下,CPU将I/O指令发出后,立即继续执行其他指令,而不是一直等待I/O设备响应结果,当I/O设备完成操作后,会向CPU发出中断信号,CPU立即暂停当前操作,转而处理中断请求。
- 直接存储器访问(DMA)方式:DMA方式是一种通过DMA控制器进行I/O设备控制的方式。在此方式下,CPU只需向DMA控制器发出指令,DMA控制器则负责管理数据传输,将数据直接从I/O设备传输到内存中,而不需要CPU的干预。相比程序控制方式和中断控制方式,DMA方式的效率更高,可以大大减少CPU的工作量。
总之,这三种I/O设备控制方式各有优缺点,应根据具体情况选择一种最适合的方式。
系统调用和库函数
系统调用和库函数都是程序与操作系统之间进行交互的方式,但它们有着不同的实现方式和使用场景。
系统调用是操作系统提供给应用程序的一组接口,用于让应用程序请求操作系统的服务。当应用程序需要访问操作系统提供的资源时(例如文件系统、网络接口、进程管理等),就可以调用系统调用完成请求。在程序执行过程中,系统调用需要进行特定的操作系统内核代码来处理,通过系统调用,应用程序可以向内核请求运行必须在特权模式下执行的操作。例如,打开/关闭文件、创建/复制/删除文件、读写文件、进程管理等等。系统调用可以看作是应用程序和操作系统之间的接口,是程序调用内核功能的唯一方式。
库函数是软件程序员对某些功能的一种封装,能够令程序员更方便地使用特定功能。库函数是由程序员自己编写的程序,包含一系列处理任务的代码。库函数可以实现程序中的细节操作,例如排序、搜索等等。库函数运行在应用程序的用户模式下,不需要特定的操作系统内核代码来支持。程序员通过链接库文件,将库函数嵌入到自己的代码中使用。
虽然系统调用和库函数都能进行资源访问和处理,但是它们的实现方式和使用场景不同,联合使用可以提高编程效率和程序性能。通常,程序员在需要操作文件、进程或网络等系统资源时,会选择使用系统调用。而在实现一些通用功能时,则会考虑使用库函数。
十五 上下文 ⭐⭐⭐⭐⭐
上下文是指程序在执行时所处的状态,包括程序当前执行的指令、程序的寄存器值、内存的内容以及其他相关的执行环境信息。
在操作系统中,上下文通常会记录在操作系统的内核态中,当一个进程被中断、被挂起或被切换时,它的上下文信息就会被保存到内存中,以便于这个进程之后可以继续执行操作。
上下文的重要性在于它包含了程序的所有状态,当系统需要切换上下文的时候,操作系统需要保存其中的状态信息并恢复之前保存的状态信息,这个过程中需要耗费时间和资源。因此,上下文切换是一个非常耗费操作系统资源和时间的操作。为了提高系统性能,我们通常需要尽量减少上下文的切换次数,以提高系统的吞吐能力。
总之,上下文是程序在执行时所处的状态,包含着程序的所有状态信息,而上下文切换则是在进行进程调度时,从一个进程切换到另一个进程所需要进行的状态切换操作。要合理使用上下文切换,尽量减少其发生次数,以提高系统的性能。
内核态与用户态的区别
内核态与用户态:内核态(系统态)与用户态是操作系统的两种运行级别。内核态拥有最高权限,可以访问所有系统指令;用户态则只能访问一部分指令。
什么时候进入内核态:共有三种方式:a、系统调用。b、异常。c、设备中断。其中,系统调用是主动的,另外两种是被动的。
为什么区分内核态与用户态:在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃。比如:清内存、设置时钟等。所以区分内核态与用户态主要是出于安全的考虑。
用户态到内核态切换方式
用户态到内核态的切换主要有以下几种方式:
- 系统调用:进程通过系统调用进入内核态执行操作,然后再返回用户态。系统调用是进程最常见的进入内核态的方式。
- 异常:例如硬件故障、软件异常等。当出现这些异常情况时,CPU会中断当前进程的执行,通过异常处理程序进入内核态进行操作,处理完成后再返回用户态。
- 外部中断:例如外设完成某个IO操作时,会向CPU发送中断信号,CPU会中断当前进程执行的用户态程序,进入中断处理程序。
对于Linux操作系统的用户态到内核态的切换来说,内核态代码和用户态代码在同一个地址空间之中,因此用户态程序和内核态程序之间的切换只需要改变CPU的执行模式和切换堆栈指针即可,不需要进行内存切换等操作。这种切换方式可以很快地完成,但是需要确保内核态代码的安全性和正确性。
内核态到用户态切换方式
内核态到用户态的切换方式主要有以下几种:
- 进程调度:当一个进程的时间片用尽或者有更高优先级的进程需要执行时,内核会切换到另一个就绪进程的上下文,并进入用户态执行该进程的用户态代码。
- 中断返回:当内核态代码执行完毕后,需要通过中断返回的方式回到用户态执行用户态代码。中断返回是通过调用IRET指令来实现的,该指令会将存储的用户态程序计数器、用户态代码段和用户态数据段的值恢复,从而让CPU重新开始执行用户态代码。
- 系统调用返回:当用户态进程进行系统调用时,内核会进入内核态执行相应的操作。当内核执行完这个操作后,会将数据传输给用户态进程,并通过系统调用返回的方式把控制权返回给用户态进程。
无论是内核态到用户态的任何一种切换方式,都需要保存内核态的上下文信息以便稍后回到内核态。当控制权回到用户态时,用户态可以恢复之前保存下来的上下文执行用户态代码,如此循环往复。
十六 磁盘存储器 ⭐⭐⭐⭐⭐
磁盘性能简述
磁盘是计算机中最主要的外部存储介质之一,其性能直接影响系统的整体性能。磁盘性能主要包括以下几个方面:
- 磁盘转速:磁盘转速越高,磁头每秒钟就可以扫描更多的数据。磁盘转速通常以每分钟转数(RPM)为单位表示,常见的磁盘转速有5400 RPM、7200 RPM、10000 RPM、15000 RPM等。
- 磁头寻道时间:即磁头从一个扇区移动到另一个扇区的时间。这个时间取决于磁头移动的距离和磁头在盘片上的位置。
- 磁盘旋转延迟时间:即磁盘旋转到需要访问的扇区的时间。这个时间也取决于磁盘的转速,以及需要访问的扇区在磁盘上的位置。
- 磁盘缓存:磁盘驱动器通常配备有缓存,用于存储最近访问的数据。磁盘缓存可以显著提高系统的读写性能,但也会增加数据互斥的概率。
- 磁盘容量:磁盘的容量决定了我们能够在磁盘上存储多少数据,在同等性能的情况下,容量更大的硬盘能够存储更多的数据。
在实际使用中,我们往往需要权衡这些因素,从而选择适合我们具体需要的磁盘配置。例如,如果需要更高的读写速度,则可以选择转速更高或者带有更大缓存的磁盘;如果需要存储更多的数据,则可以选择容量更大的磁盘。
磁盘调度算法
磁盘调度算法是指操作系统中用来管理磁盘访问请求的算法。由于磁盘的访问速度比内存慢得多,所以操作系统需要一个磁盘调度算法来优化磁盘I/O操作的顺序。
常见的磁盘调度算法有以下几种:
- 先来先服务(FCFS):按照请求的到达时间优先级进行服务。
- 最短寻道时间优先(SSTF):选择与当前磁头位置最近的请求优先处理。
- 扫描算法(SCAN):沿着一个方向移动磁头,直到磁头到达边界,然后改变方向并继续移动磁头。
- 循环扫描算法(C-SCAN):类似于SCAN的算法,不同之处在于扫描完最后一个请求后,立即返回到最前面的请求处,重新开始扫描。
- 最大响应时间优先(LRTF):优先响应等待时间最长的请求。
不同的磁盘调度算法有不同的优点和缺点,选择哪种算法主要取决于具体的应用场景和需求。比如,对于磁盘访问压力较大的情况,选择优先响应等待时间最长的LRTF算法能够最大限度地减少请求的等待时间;而对于磁盘访问压力较小的情况,则可以选择FCFS算法,由于算法简单,易于实现并可以避免其他算法产生的大量寻头操作。
十七 文件管理 ⭐⭐⭐⭐⭐
文件和文件系统
文件是操作系统中的重要概念,它是一种持久存储数据的方式,可以被操作系统和程序访问。通常,文件包含由字符、字节或二进制数据组成的文本、图像、音频、视频等内容。
文件系统是一种操作系统功能,用于管理和组织文件的存储和访问。每个文件系统都有独特的组织方式,可以对文件进行分组和存储,以便快速访问和管理。文件系统可以存在于硬盘、闪存、网络存储等各种设备中,并提供了一些标准化的操作和API,使得操作系统和应用程序可以方便地操作文件。
文件系统通常包括以下几个组成部分:
- 目录结构:用来组织和管理文件的层次结构。
- 文件元数据:包括文件名、文件类型、大小、创建时间、修改时间、访问权限等信息。
- 文件存储:用于存储文件数据的设备,如硬盘、闪存等。
- 文件访问机制:用于控制对文件的访问,如读、写、删除等。
文件系统允许用户通过一些标准的操作来访问和管理文件,如打开、关闭、读取和写入文件等。它也提供了高级功能,如文件共享、加密、压缩和备份等。不同的操作系统和设备可能使用不同的文件系统,如Windows系统使用NTFS、FAT和FAT32文件系统,而Linux系统经常使用EXT4文件系统。
文件的逻辑结构
文件的逻辑结构通常由两个方面组成:文件的数据组成和文件的记录组织方式。
文件的数据组成是指文件中存储的内容,这些内容可能是字符、字节、二进制数据、图像、音频等。不同的文件类型可能有不同的数据组成方式,例如文本文件一般由文本字符组成,图像文件则由像素点组成。
文件的记录组织方式是指文件中数据的组织结构,即如何将数据划分为记录,以便于访问和修改。文件中的记录通常有固定长度或变长,可以按顺序或者按索引方式组织。不同的文件类型也可能采用不同的记录组织方式,例如关系型数据库中的表就是一种按记录方式组织的文件。
总的来说,文件的逻辑结构关注的是文件中数据的存储方式和组织结构,也是操作系统和应用程序访问和处理文件必须了解和考虑的因素。
文件目录和树形结构目录
文件目录是文件系统中用于组织和管理文件的一种结构,在大多数操作系统中都是使用树形结构的目录。
树形结构目录是一种层级结构,类似于家谱或部门架构图表。在文件系统中,目录可以包含文件和其他目录,每个节点都有一个名称和一个特殊的父节点,除了根节点外,每个目录节点都有一个父节点和零个或多个子节点。
树形结构目录的优点在于简单和直观,任何一个节点都可以通过其唯一的路径名(即节点的名称及其所有上层目录的名称)来访问。此外,文件系统利用目录结构可以帮助用户方便地组织、查找和管理大量的文件。
在树形结构目录中,每个节点的名称是唯一的,在同一级目录下不得重复。如果两个文件或目录在同一个目录下具有相同的名称,则称为名称冲突。为了避免名称冲突,通常在不同的目录下使用不同的名称。
总的来说,文件目录和树形结构目录是文件系统中重要的组成部分,它们共同构成了管理和组织文件的框架,也是操作系统和应用程序访问和处理文件必须了解和考虑的因素。
文件共享
文件共享是指多个计算机之间共享同一份文件。在一个网络环境中,文件共享可以方便地在多个计算机之间共享文件,从而提高工作效率和便利性。常用的文件共享技术包括以下几种:
- 局域网络(LAN)共享:局域网络是一种基于物理线缆或无线信号的网络,适用于小范围内的计算机之间共享文件和资源。
- 远程文件访问(Remote File Access):远程文件访问是一种通过互联网或其他远程网络连接访问文件的技术。用户需要连接到远程计算机,从而实现对共享文件的访问和操作。
- 云存储共享:云存储是一种通过云服务提供商存储数据的方式,用户可以通过网络访问和共享存储在云存储服务上的文件。
- 文件传输协议(FTP):FTP是一种用于在计算机之间传输文件的协议,它可以在局域网和互联网上进行文件共享。用户可以通过FTP客户端连接到FTP服务器,从而实现对共享文件的访问和传输。
- 共享文件夹:在局域网中,用户可以创建共享文件夹,以使其他计算机可以访问该文件夹中的文件。这需要在网络设置中启用文件共享功能,并设置共享文件夹的权限以控制访问权限。
文件共享的优点是方便、高效、节省存储空间和减少数据冗余。然而,文件共享也存在一些安全风险,因此需要采取适当的安全措施,如设置访问权限、加密传输和监控共享文件的使用情况。
文件保护
在计算机系统中,文件保护是非常重要的。以下是一些文件保护措施:
- 文件权限:文件权限是通过为每个文件分配访问权限来保护文件的安全性。这些权限可以控制用户对文件的读、写和执行权限。只有拥有特定权限的用户才能访问文件。
- 文件加密:文件加密是一种保护文件机密性的方法。通过加密,只有具有密钥的人才能解密并访问文件内容。
- 防病毒软件:电脑上安装防病毒软件可以避免系统受到恶意软件或病毒的攻击,从而保护文件和数据的安全。
- 定期备份:定期备份文件是保护文件的一种方法,备份可以帮助恢复意外删除、丢失或损坏的文件。
- 硬件防护:使用防火墙、VPN等硬件设备可以保护文件的安全性,阻止恶意攻击者从互联网入侵系统。此外,使用加密USB驱动器和锁定计算机来保护存储在设备上的数据通常也是有用的。
综上所述,保护文件的安全是非常重要的,需要多种措施来增加文件的安全性。在日常使用文件的同时,必须注意谨慎操作,勿轻信邮件、加好友等诱骗信息。
十七 磁盘存储器的管理 ⭐⭐⭐⭐⭐
外存的组织方式
1连续组织方式
连续组织方式是一种比较简单的文件组织方式,也称为顺序文件组织方式。在连续组织方式中,文件中的记录按照逻辑顺序连续存储在外存设备中。每个记录都有一个唯一的编号(也称为键),这个编号用于访问记录。
与其他文件组织方式相比,连续组织方式的优点是文件读取速度快,文件大小易于控制,存储空间利用率高。但也存在一些缺点,比如插入、删除和更新记录时会比较复杂,文件中的空洞会影响存储空间利用率,文件可能会发生碎片化等问题。
连续组织方式适用于数据访问较为频繁且读取速度要求高、文件大小较小且文件格式稳定的情况。常见的应用场景包括音频、视频、图片等媒体文件的存储,以及序列化数据的存储等。
2链接组织方式
链接组织方式是一种文件组织方式,也称为链式文件组织方式。在链接组织方式中,文件中的记录存储在任意位置上,每个记录通过一个指向下一个记录位置的指针来与其后继记录相连接。因此,整个文件的记录组成了一个链表,可以通过遍历链表来访问其中的记录。
链接组织方式相对于连续组织方式,虽然记录存储在任意位置上,但却使文件更新、插入、删除更加容易。由于每个记录都有一个独立的指针,所以各个记录可以灵活地组织在一起,不会像连续组织方式一样被限制住。同时,链接组织方式还具有文件大小易于扩展的优点。
但链接组织方式也面临着一些问题,如无法有效地控制文件碎片化和指针的管理等问题。
链接组织方式适用于数据操作频率不高、记录大小较小、记录的组织结构不稳定且需要频繁修改的情况。常见的应用场景包括字典、电话簿等小型文件的存储,以及动态产生数据的存储等。
3索引组织方式
索引组织方式是一种文件组织方式,它使用索引表来帮助快速定位、检索文件中的记录。在索引组织方式中,每个记录除了存在于文件本身之外,还存在于一个或多个索引表中。索引表包含了记录的关键字和一个指向文件记录的地址。通过查找索引表,可以快速定位到所需要的记录。
索引组织方式相对于链接组织方式和连续组织方式,具有更快的检索速度和更好的文件碎片化控制。此外,索引表的建立和更新可以自动进行,无需手动管理指针,更便于维护。
但索引组织方式也面临着一些问题,比如索引表占据的空间较多,可能会导致存储空间浪费和查询效率下降。此外,在索引表和文件之间增加了一层结构,可能会增加文件操作的复杂性和时间开销。
索引组织方式适用于数据操作频率较高、记录较大、记录之间存在复杂关系的情况。常见的应用场景包括数据库管理系统、文件检索系统、报表系统等需要大量数据检索和分析的场合。
文件存储空间的管理方法
1 空闲表法
空闲表法是一种常见的文件存储空间管理技术之一,它的主要思想是将文件占用的存储单元划分为若干大小相等的块,再将未被占用的块组织成一个空闲块表,用一个指针指向这个表的第一个空闲块。操作系统在分配空间时,从这个表中取出一个空闲块,并将指针指向下一个空闲块。当一个文件被删除时,将该文件占用的块归还给空闲块表。这种方法的优点是实现简单、易于维护,但很容易产生碎片。
空闲表法具体的实现步骤如下:
- 将整个磁盘空间划分成若干大小相等的块,每个块大小为文件系统管理的最小存储单位。
- 维护一个空闲块链表,链表中的每个节点记录一个空闲块的起始地址和长度。
- 当空闲块链表中的第一个节点被取出时,将该节点的信息返回给申请者,并将指针指向下一个节点。
- 当有新文件需要存储时,根据文件大小从链表中查找合适的空闲块,若找到了,将该空闲块划分为文件所需的大小,并从空闲块链表中删除该块。
- 当一个文件被删除时,将该文件占用的所有空间块加入空闲块链表中,并将空闲块链表重新连接起来,以便缩小外部碎片。
空闲表法主要的弱点是容易出现碎片,导致磁盘空间浪费,因此在实际应用中,大多数文件系统都将空闲表法与其他管理技术相结合,例如位图法、索引法等,以达到更好的文件存储空间管理效果。
2 空闲链表法
空闲链表法是一种文件存储空间管理技术,它与空闲表法类似,也是将整个磁盘空间划分为若干大小相等的块,并将未被占用的块组成一个单向链表,用一个指针指向这个链表的第一个空闲块。操作系统在分配空间时,从这个链表中取出一个空闲块,并将指针指向下一个空闲块。当一个文件被删除时,将该文件占用的块加入链表的头部。
与空闲表法不同的是,空闲链表法不需要维护每个空闲块的具体信息,而是每个空闲块只需记录下一个空闲块的地址,这样就可以通过一个单向链表轻松地实现磁盘的空闲块管理。
空闲链表法的优点是实现简单、容易维护,能够充分利用磁盘空间,减少碎片的产生。缺点是空间利用率较低,如果每个块过小,则会造成链表指针的开销过大;如果每个块过大,可能会出现较为严重的外部碎片。
空闲链表法是文件系统中常见的一种存储空间管理技术,一些常见的文件系统,如Unix文件系统、Linux文件系统等,都使用了空闲链表法和其他管理技术相结合的方法,以获得更好的文件存储空间管理效果。
3 位示图法
位示图法也是文件存储空间管理的一种方法。该方法将整个磁盘空间按照一定大小的块进行划分,每个块对应于位示图上的一个二进制位,用1表示该块已分配,用0表示该块未分配。操作系统中存维护一个位示图,操作系统在进行分配和回收操作时,就通过位示图上相应的二进制位的状态来判断该磁盘块是否空闲或已分配。
位示图法的优点是空间利用效率很高,因为位示图法可以非常精确地确定每个块的状态,并且不会出现碎片问题。缺点是实现和维护相对繁琐,因为需要维护一个与磁盘空间大小相同的位示图,而且在位示图非常大时,它需要使用较多的内存。
位示图法是现代操作系统中经常使用的一种文件存储空间管理技术,如FAT文件系统和NTFS文件系统等。它比起空闲链表法的维护相对复杂,但同时在硬件性能越来越强大的现代计算机环境下,位示图提供了更精确管理存储空间的能力。
4 成组链接法
成组链接法是另一种常见的文件存储空间管理方法。它将整个文件存储空间划分成若干组,每组包含若干物理块。每个组都有一个指向下一组的指针,形成一个链表。在进行文件分配时,同一文件的所有物理块被存储在同一组中,文件的每个物理块通过链表相连。当需要回收某个文件时,只需将该文件所在组的所有物理块从链表中删除,并置位空闲标志位。
成组链接法的优点是能够防止出现外部碎片,同时在磁盘使用率较高时,也能够保证比较高的性能。缺点是存在内部碎片,因为每个文件所需要的物理块数量不一定能够填满整个组。而且由于需要遍历链表来查找文件,因此其性能较差,它们很少被现代操作系统使用。
总体来说,成组链接法在存储空间利用率和外部碎片的处理方面比较优秀。它在一些较小的系统中仍然被大量使用,但在现代操作系统中,它通常被更高效的方法所替代。
十八 Linux Shell 命令语言 ⭐⭐⭐⭐⭐
Linux Shell是Linux中用于与用户进行交互的命令行界面(CLI)。通过Shell,用户可以输入各种命令,执行文件、管理文件系统、编辑文件等任务。
以下是一些常用的Linux Shell命令语言:
- ls:列出目录下的文件和子目录。
- cd:更改当前的工作目录。
- cat:显示一个或多个文件的内容。
- cp:复制文件或目录。
- mv:移动文件或目录,或对文件更名。
- rm:删除文件或目录。
- mkdir:创建一个新目录。
- rmdir:删除一个空目录。
- touch:创建一个新文件或更改时间戳。
- chmod:更改文件或目录的权限。
- chown:更改文件或目录的所有者。
- ps:列出系统上的进程。
- kill:结束一个进程。
- ping:测试网络连接状态。
- ssh:基于SSH协议远程登录到其他计算机系统。
这些是一些常见的Linux Shell命令,但还有很多其他命令可供使用。熟练掌握这些命令将使您能够更有效地管理您的Linux系统。
十九 文件权限如何修改 ⭐⭐⭐⭐⭐
Linux文件的基本权限就有九个,分别是owner/group/others三种身份各有自己的read/write/execute权限
修改权限指令:chmod
答案解析
举例:文件的权限字符为 -rwxrwxrwx 时,这里总共会有10个字符,第一个字符表示文件类型,如文件(-表示),文件夹(d表示),链接文件(l表示),块设备(b表示),字符设备(c表示),后面9个字符按照三个一组分。其中,我们可以使用数字来代表各个权限。
各权限的分数对照如下:
r w x 4 2 1
每种身份(owner/group/others)各自的三个权限(r/w/x)分数是需要累加的,
例如当权限为: [-rwxrwx—] ,则分数是:
owner = rwx = 4+2+1 = 7 group = rwx = 4+2+1 = 7 others= --- = 0+0+0 = 0
所以我们设定权限的变更时,该文件的权限数字就是770!变更权限的指令chmod的语法是这样的:
[root@www ~]# chmod [-R] xyz 文件或目录 选项与参数: xyz : 就是刚刚提到的数字类型的权限属性,为 rwx 属性数值的相加。 -R : 进行递归(recursive)的持续变更,亦即连同次目录下的所有文件都会变更 # chmod 770 douya.c //即修改douya.c文件的权限为770
二十 常见信号有哪些,表示什么含义?⭐⭐⭐⭐⭐
常见信号如下:
信号代号 信号名称 说 明
其中最重要的就是 “1”、“9”、“15”、"17"这几个信号。
#操作系统##嵌入式#该专栏面向嵌入式开发工程师,包括C语言、C++,操作系统,ARM架构、RTOS、Linux基础、Linux驱动、Linux系统移植、计算机网络、数据结构与算法、5篇面试题目、HR面试常见问题汇总和嵌入式面试简历模板等18篇文章。超全的嵌入式软件工程师笔试面试题目和高频知识点总结!招聘so easy。