系列文章目录
C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
期待你的关注哦!!!
现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.
Linux操作系统体系结构
要想把程序编好,必须对Linux操作系统体系结构有所了解,一般来说传统的Linux操作系统体系结构如图:
一般情况下,Linux操作系统的结构体系分为用户态和内核态。
1、操作系统/内核
- 软件
用于控制计算机的硬件资源,提供应用程序运行的环境。之所以称为内核,是因为比较小,且位于整个体系结构的核心。
我们编写的程序,要么运行在用户态,要么运行在内核态
,一般情况下运行在用户态,当程序要执行一些特殊代码时,程序就可能切换到内核态。这种切换有操作系统控制,不需要认为介入。
换一个角度理解用户态和内核态,用户态可以理解为图1中最外圈应用程序的活动空间。但是,我们所开发的应用程序的运行,往往需要访问一些资源(如读写文件要访问磁盘,调用malloc要申请内存,程序中可能还要访问传真机、打印机等外部设备),为了让应用程序能够访问这些资源,内核必须提供供应用程序访问的接口,也就是图1中的系统调用(内核对外接口)。
2、系统调用
其实就是一些库函数,写代码时调用即可
一般情况,操作系统会提供200~300个库函数供我们调用,这些库函数在系统内部高度封装,我们无需关心细节,只需调用即可。
3、shell
是一个命令行解释器,是Linux系统中用户与操作系统内核交互的主要方式之一
当用Xshell链接Ubuntu Linux虚拟机的时候,使用ps命令查看,就能看到一个bash进程(这个bash进程是自动开启的,用Xshell链接虚拟机时,系统就启动了一个bash。这个bash是被login/sshd用fork函数开启的。)
bash是borne again shell (重新装配的shell)的缩写,是shell的一种,Linux默认采用bash这种shell。
通俗地说,bash也是一个可执行程序,这种可执行程序的主要作用是:把用户输入的命令翻译给操作系统,所以bash相当于一个命令解释器。
bash也可以手动创建,因为它是一个可执行程序。
尝试用whereis找到bash的位置,直接执行,然后使用exit退出当前的bash,如图:
如果第二次输入exit,则会从当前使用的bash中退出Xshell会与Ubuntu Linux虚拟机断开连接(因为第一次突退出的是自己执行的bash,第二次退exit退出的是login/sshd进程用函数fork创建的bash进程)。
观察图1中shell的位置,它正好夹在系统调用和应用程序之间,起分隔系统调用和应用程序的作用,同时也有胶水(将系统调用和应用程序黏在一起)的感觉。
操作系统的内核部分,有进程管理,文件系统、设备驱动、网络等各种资源的管理。在内核和用户空间之间,通过系统调用(system call)接口实现对各种资源功能的调用。
4 、用户态
和内核态
之间的切换
编写的程序要么运行在用户态,要么运行在内核态,2种状态必居其一。运行于用户态的进程可执行爱那个的操作和可访问的资源都受到了极大的限制(用户态权限极小),而运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制(内核态权限比较大)。
一个程序执行过程中,大部分时间都处于用户态,只有需要内核所提供的服务时才切换到内核态,内核态的任务处理完成后,又切换回用户态。如C函数库中的内存分配函数malloc,其内部会使用sbrk系统调用来分配内存,当malloc调用sbrk的时候就涉及一次从用户态到内核态的切换。类似的函数还有printf使用write系统调用来输出字符串,等等。这种状态转换由操作系统来完成,不需要我们介入。
(1)用户态权限小,内核态权限大,权限大意味着能做一些危险的事(如处理内存、处理时钟),如果所有用户程序都能做这些事,就可能经常出现错用乱用,导致系统处于危险状态甚至崩溃。所以,一般情况下,程序都处于用户态,只有需要做一些危险的事情时,系统才提供一些调用接口,让程序切换到内核态。
(2)这些调用接口是系统提供并统一管理的。操作系统资源有限,如果许多程序同时访问这些资源,一旦产生访问冲突,或资源耗尽,就可能导致系统崩溃,所以,系统提供这些接口,就是为了减少有限的资源访问以及使用上的冲突。
比如现在要看电影,有100个人要买票,就不能让100人同时买,否则大家挤成一团,谁也抢不到票。所以设立售票窗口(接口),售票窗口里有一个专门卖票的人,这100个买票的人需要逐个买。
什么时候会从用户态跳到内核态?
系统调用
。如上述的malloc。异常事件
。如接收到某个信号,代码中写了一段信号处理函数,系统就可能需要跳到内核态去做一些调用该信号处理函数的准备工作。外围设备的中断
。外围设备完成用户的请求操作后,会向CPU发出中断信号,此时CPU就会暂停执行下一条即将执行的指令,转而去执行中断信号对应的处理程序,如果先前执行的指令是在用户态下,就会发生从用户态到内核态的转换。