C/C++后端开发面经(5)——linux操作系统

C/C++后端开发面经(5)——linux操作系统

  • 1 Linux系统基础
    • 1.1 linux常用命令
    • 1.2 Linux 操作系统挂起、休眠、关机相关命令⭐⭐
  • 2 Linux内核相关
    • 2.1 Linux内核的组成⭐⭐
    • 2.2用户空间与内核通信方式有哪些?⭐⭐⭐⭐⭐
    • 2.3系统调用read()/write(),内核具体做了哪些事情⭐⭐
    • 2.4系统调用的作用⭐⭐⭐⭐⭐
    • 2.5内核态,用户态的区别⭐⭐⭐⭐⭐
    • 2.6 bootloader内核 根文件的关系⭐⭐⭐⭐
    • 2.7 Bootloader多数有两个阶段的启动过程:⭐⭐⭐
    • 2.8 linux的内核是由bootloader装载到内存中的?⭐⭐⭐
    • 2.9为什么需要BootLoader⭐⭐⭐⭐
    • 2.10 Linux内核同步方式总结⭐⭐⭐⭐
    • 2.11为什么自旋锁不能睡眠 而在拥有信号量时就可以?⭐⭐⭐⭐
    • 2.12 linux下检查内存状态的命令⭐⭐⭐

公钥和秘钥

1 Linux系统基础

1.1 linux常用命令

C/C++后端开发面经(5)——linux操作系统_第1张图片C/C++后端开发面经(5)——linux操作系统_第2张图片
在这里插入图片描述

1.2 Linux 操作系统挂起、休眠、关机相关命令⭐⭐

解析:
参考:https://blog.csdn.net/uncleunclelee/article/details/52993629
挂起
是一种省电模式,系统将机器的硬盘、显示器等外部设备停止工作,而CPU、内存仍然工作,等待用户随时唤醒,再次唤醒需要按键盘上的键数次。
体眠
是一种更加省电的模式,它将内存中的数据保存于硬盘中,使CPU也停止工作,当再次使用时需按开关机键,机器将会恢复到您的执行休眠时的状态,而不用再次执行启动操作系统复杂的过程。
待机是将当前处于运行状态的数据保存在内存中,机器只对内存供电,而硬盘、屏幕和CPU等部件则停止供电。由于数据存储在速度快的内存中,因此进入等待状态和唤醒的速度比较快。不过这些数据是保存在内存中,如果断电则会使数据丢
关机重启:
关机命令有halt, init 0, poweroff ,shutdown -h时间,其中shutdown是最安全
重启命令有reboot,init 6,,shutdow -r时间
在linux命令中reboot是重新启动,shutdown -r now是立即停止然后重新启动,都说他们两个是一样的,其实是有一定的区别的。
shutdown命令可以安全地关闭或重启Linux系统,它在系统关闭之前给系统上的所有登录用户提示一条警告信息。该命令还允许用户指定一个时间参数,可以是一个精确的时间,也可以是从现在开始的一个时间段。
精确时间的格式是hh:mm,表示小时和分钟,时间段由+ 和分钟数表示。系统执行该命令后会自动进行数据同步的工作。
该命令的一般格式: shutdown [选项] [时间] [警告信息]
命令中各选项的含义为:

  • k 并不真正关机而只是发出警告信息给所有用户
  • r 关机后立即重新启动
  • h 关机后不重新启动
  • f 快速关机重启动时跳过fsck
  • n 快速关机不经过init 程序
  • c 取消一个已经运行的shutdown
    需要特别说明的是该命令只能由超级用户使用。
    例1,系统在十分钟后关机并且马上重新启动: # shutdown –r +10 再重新启动linux系统的同时把内存中的信息写入硬盘
    例2,系统马上关机并且不重新启动:# shutdown –h now
    halt是最简单的关机命令,其实际上是调用shutdown -h命令。halt执行时,杀死应用进程,文件系统写操作完成后就会停止内核。
    halt命令的部分参数如下:
    [-f] 没有调用shutdown而强制关机或重启
    [-i] 关机或重新启动之前,关掉所有的网络接口
    [-p] 关机时调用poweroff,此选项为缺省选项

reboot的工作过程与halt类似,其作用是重新启动,而halt是关机。其参数也与halt类似。reboot命令重启动系统时是删除所有的进程,而不是平稳地终止它们。因此,使用reboot命令可以快速地关闭系统,但如果还有其它用户在该系统上工作时,就会引起数据的丢失。所以使用reboot命令的场合主要是在单用户模式。
init是所有进程的祖先,其进程号始终为1。init用于切换系统的运行级别,切换的工作是立即完成的。init 0命令用于立即将系统运行级别切换为0,即关机;init 6命令用于将系统运行级别切换为6,即重新启动

2 Linux内核相关

2.1 Linux内核的组成⭐⭐

解析:
参考: http://www.elecfans.com/emb/20180124622496.html
UNIX系统由内核、shell、文件系统(系统调用和共用函数库)和应用程序等4部分组成。
一.Linux内核
内核是操作系统的核心,具有很多最基本功能,如虚拟内存、多任务、共享库、需求加载、可执行程序和TCP/IP网络功能。Linux内核的模块分为以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信、系统的初始化和系统调用等。
二.Linux shell
shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行,是一个命令解释器。另外,shell编程语言具有普通编程语言的很多特点,用这种编程语言编写的shell程序与其他应用程序具有同样的效果。
三.Linux文件系统
文件系统是文件存放在磁盘等存储设备上的组织方法。Linux系统能支持多种目前流行的文件系统,如EXT2、EXT3、FAT、FAT32、VFAT和ISO9660。
四.Linux应用程序
标准的Linux系统一般都有一套都有称为应用程序的程序集,它包括文本编辑器、编程语言、XWindow、办公套件、Internet工具和数据库等。

内核分为 进程管理系统、内存管理系统、I/O管理系统和文件管理系统 等四个子系统

2.2用户空间与内核通信方式有哪些?⭐⭐⭐⭐⭐

解析:
1)首先想到的是系统调用,用户空间进程通过系统调用进入内核空间,访问指定的内核空间数据;
2).其次是驱动程序,用户空间进程可以使用封装后的系统调用接口访问驱动设备节点,以和运行在内和空间的驱动程序通信;
3).共享内存mmap,在代码中调用接口,实现内核空间与用户空间的地址映射,在实时性要求很高的项目中为首选,省去拷贝数据的时间等资源,但缺点是不好控制;
4).最后,copy_to_user()、copy_from_user(),是在驱动程序中调用接口,实现用户空间与内核空间的数据拷贝操作,应用于实时性要求不高的项目中。

问: IPC(进程间通信)机制中最快的,可以跨进程的是什么?
答:共享内存。

我们可以看出,共享内存的消息复制只有两次。一是,从输入文件到共享内存;二是,从共享内存到输出文件。这样就很大程度上提高了数据存取的效率。
我们可以看出,共享内存的消息复制只有两次。一是,从输入文件到共享内存;二是,从共享内存到输出文件。这样就很大程度上提高了数据存取的效率。
以下这个问题忘了哪里看到的,当时也保存下来,但比较少接触到,读者当作阅读看看即可。
问:Linux的用户态与内核态的转换方法?
解答:Linux下内核空间与用户空间进行通信的方式主要有syscall(system call)、procfs、ioctl和netlink等。还有copy_to_user copy_from_user共享内存mmap 驱动
1)syscall:
一般情况下,用户进程是不能访问内核的。它既不能访问内核所在的内存空间,也不能调用内核中的函数。Linux内核中设置了一组用于实现各种系统功能的子程序,用户可以通过调用他们访问linux内核的数据和函数,这些系统调用接口(SCI)称为系统调用;
2)procfs:
是一种特殊的伪文件系统 ,是Linux内核信息的抽象文件接口,大量内核中的信息以及可调参数都被作为常规文件映射到一个目录树中,这样我们就可以简单直接的通过echo或cat这样的文件操作命令对系统信息进行查取;应该就是根目录里的/proc
3)netlink:
用户态应用使用标准的socket API就可以使用netlink提供的强大功能;
4)ioctl:
函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道。

在这几个通信方式中,效率最高的方式,选择netlink,原因如下:
全双工:procfs是基于文件系统,用于内核向用户发送消息;syscall是用户访问内核。它们都是单工通信方式。netlink是一种特殊的通信方式,用于在内核空间和用户空间传递消息,是一种双工通信方式。使用地址协议簇AF_NETLINK,使用头文件include/linux/netlink.h;
易于添加:为新特性添加system call、或者procfs是一件复杂的工作,它们会污染kernel(内核),破坏系统的稳定性,这是非常危险的。Netlink的添加,对内核的影响仅在于向netlink.h中添加一个固定的协议类型,然后内核模块和应用层的通信使用一套标准的API。

2.3系统调用read()/write(),内核具体做了哪些事情⭐⭐

参考:https://blog.csdn.net/qq_27977257/article/details/55100638
解析:本题是本人曾亲自被问到,但感觉还是比较少人会问此问题,所以可能其他人的面经没有这个问题,读者可稍微了解即可。
用户空间read()–>内核空间sys_read()–>scull_fops.read–>scull_read();
该过程分为两个部分:用户空间的处理和核心空间的处理。在用户空间中通过 0x80 中断的方式将控制权交给内核处理,内核接管后,经过6个层次的处理最后将请求交给磁盘,由磁盘完成最终的数据拷贝操作。在这个过程中,调用了一系列的内核函数

2.4系统调用的作用⭐⭐⭐⭐⭐

解析:
1、为了管理硬件资源和为应用程序开发人员提供良好的环境来使应用程序具有更好的兼容性,为了达到这个目的,内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序。
2、具有多任务处理的功能,通常靠进程来实现。
有必要提供接口来为应用程序提供诸如读取磁盘某位置的数据的接口,这些接口就被称为系统调用。
4、当操作系统接收到系统调用请求后,会让处理器进入内核模式,从而执行诸如I/O操作,修改基址寄存器内容等指令,而当处理完系统调用内容后,操作系统会让处理器返回用户模式,来执行用户代码。

2.5内核态,用户态的区别⭐⭐⭐⭐⭐

解析:
参考:https://blog.csdn.net/qq_39823627/article/details/78736650
系统态(也称为管态或核心态),操作系统在系统态运行——运行操作系统程序
用户态(也称为目态),应用程序只能在用户态运行——运行用户程序
当一个进程在执行用户自己的代码时处于用户运行态(用户态),此时特权级最低,为3级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态。Ring3状态不能访问Ring0的地址空间,包括代码和数据;当一个进程因为系统调用陷入内核代码中执行时处于内核运行态(内核态),此时特权级最高,为0级。执行的内核代码会使用当前进程的内核栈,每个进程都有自己的内核栈。
用户运行一个程序,该程序创建的进程开始时运行自己的代码,处于用户态。如果要执行文件操作、网络数据发送等操作必须通过write、send等系统调用,这些系统调用会调用内核的代码。进程会切换到Ring0,然后进入3G-4G中的内核地址空间去执行内核代码来完成相应的操作。内核态的进程执行完后又会切换到Ring3,回到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。这说的保护模式是指通过内存页表操作等机制,保证进程间的地址空间不会互相冲突,一个进程的操作不会修改另一个进程地址空间中的数据。

2.6 bootloader内核 根文件的关系⭐⭐⭐⭐

解析:
参考:https://blog.csdn.net/zhangcanyan/article/details/81409053
启动顺序:bootloader->linuxkernel->rootfile
后者需要前者提供功能支持,前者的目的就是启动后者。
嵌入式Linux系统启动过程Linux引导的整个过程:当系统首次引导时,或系统被重置时,处理器会执行一个位于Flash/ROM中的已知位置处的代码,Bootloader就是这第一段代码。它主要用来初始化处理器及外设,然后调用Linux内核。Linux内核在完成系统的初始化之后需要挂载某个文件系统作为根文件系统(RootFilesystem),然后加载必要的内核模块,启动应用程序。
(一个嵌入式Linux系统从软件角度看可以分为四个部分:引导加载程序(Bootloader),Linux内核,文件系统,应用程序。)
嵌入式Linux系统通过Bootloader引导,一上电,就要执行Bootloader来初始化系统。在完成对系统的初始化任务之后,它会将非易失性存储器(通常是Flash或DOC等)中的Linux内核拷贝到RAM中去,然后跳转到内核的第一条指令处继续执行,从而启动Linux内核。Bootloader和Linux内核有着密不可分的联系。

2.7 Bootloader多数有两个阶段的启动过程:⭐⭐⭐

解析:
Stage1:是汇编的
1)基本的硬件初始化(关闭看门狗(单片机程序中为什么要禁止看门狗http://www.sohu.com/a/122050439_505888)和中断,MMU(带操作系统),CACHE。 配置系统工作时钟)
2)为加载stage2准备RAM空间
3)拷贝内核映像和文件系统映像到RAM中
4)设置堆栈指针sp
5)跳到stage2的入口点
Stage2:c语言的
1)初始化本阶段要使用到的硬件设备(led uart等)
2)检测系统的内存映射
3)加载内核映像和文件系统映像
4)设置内核的启动参数
嵌入式系统中广泛采用的非易失性存储器通常是Flash,而Bootloader就位于该存储器的最前端,所以系统上电或复位后执行的第一段程序便是Bootloader。

2.8 linux的内核是由bootloader装载到内存中的?⭐⭐⭐

解析:linux的内核的确是由bootloader装载到内存中的。linux的bootloader有2个部分组成:bootstrap和uboot。所以更准确点的说法是:linux的内核是由uboot装载到内存中的。内核文件本身是存放在硬盘的文件系统中,这句话就是错的。内核和文件系统是分开存储的。uboot读取kernel到内存是从kernel开始存储的地址开始读取的,而读取开始位置和读取大小,是由环境变量决定的。所以这个时候不需要文件系统的。
给你张图片,便于理解吧。这张图片是bootstrap、uboot、环境变量、kernel、文件系统在nandflash里面的存储分布

2.9为什么需要BootLoader⭐⭐⭐⭐

答:整个系统的加载启动任务就完全由BootLoader来完成。BootLoader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。

2.10 Linux内核同步方式总结⭐⭐⭐⭐

解析:
内核抢占:如果进程正在执行内核函数时(即它在内核态运行时),允许发生内核切换(被替换的进程是正在执行内核函数的进程),这个内核就是抢占的。

运行在内核态的进程可以自动放弃cpu,称为计划性进程切换,抢占式内核中,进程被迫放弃CPU,称为强制性进程切换。抢占内核的主要特点是:一个内核态运行的进程,可能在执行内核函数期间被另一个进程取代。

内核抢占就会发生一种情况:两个或两个以上的交叉内核路径嵌套时,就可能出现竞争条件。还有一种情况,多核环境下,多个core上的进程同时进入内核,就会出现访问的竞争。因此内核需要同步。内核同步技术主要有以下方式:
2.原子操作6.顺序锁8 信号量
参考:https://blog.csdn.net/yyf_it/article/details/52416994

2.11为什么自旋锁不能睡眠 而在拥有信号量时就可以?⭐⭐⭐⭐

参考:https://blog.csdn.net/bailyzheng/article/details/8018518
解析:
自旋锁禁止处理器抢占;而信号量不禁止处理器抢占。
基于这个原因,如果自旋锁在锁住以后进入睡眠,由于不能进行处理器抢占,其他系统进程将都不能获得CPU而运行,因此不能唤醒睡眠的自旋锁,因此系统将不响应任何操作(除了中断或多核的情况,下面会讨论)。而信号量在临界区睡眠后,其他进程可以用抢占的方式继续运行,从而可以实现内存拷贝等功能而使得睡眠的信号量程序由于获得了等待的资源而被唤醒,从而恢复了正常的代码运行。

2.12 linux下检查内存状态的命令⭐⭐⭐

1)top
2)free
3)cat /proc/meminfo
4)vmstat
问:linux中怎么查看堆栈
答:有两种方法:
第一种:pstack进程ID
第二种,使用gdb然后attach进程ID,然后再使用命令thread apply all bt
5.1.13 linux内核移植过程
嵌入式Linux系统移植主要由四大部分组成:
第一部分:搭建交叉开发环境
硬件组成
1.开发主机
2.目标机(开发板)
3.二者的链接介质,常用的主要有3中方式:(1)串口线 (2)USB线 (3)网线

第二部分:bootloader的选择和移植

第三部分:kernel的配置、编译、和移植

一、将下载好的linux-2.6.35.tar.bz2拷贝到主目录下解压
二、修改顶层目录下的Makefile,主要修改平台的体系架构和交叉编译器

第四部分、根文件系统的制作

你可能感兴趣的:(面经,C++,c++)