掘金 后端 ( ) • 2024-04-07 11:23

操作系统

1、在分页模式下,操作系统是如何对应用程序的地址空间进行隔离的?

关键词:虚拟地址、MMU页表 实模式下多个任务共享所有地址空间太危险, 因此才有了保护模式,保护模式下的分页模式是一个巨大的创新。 对于每个进程而言,它会误认为(被操作系统欺骗)自己独有所有地址空间,因此它访问地址是 不会考虑任何问题的,可是这个地址是虚拟地址,待被MMU翻译后会得到对应的页表,而这 个页表由操作系统管理,不同的进程拥有不同的页表,也因此产生了进程地址空间隔离,但是 多个进程也是可以共享某个页表,这也是进程通信(IPC)的根本手段 2、多线程下的并发、信号量、重入锁等机制

整理一下结构

1、进程的内存地址空间用一个 mmadrsdsc_t结构表示 2、mmadrsdsc_t结构中包括一个virmemadrs_t结构,管理了进程全部kmvarsdsc_t结构【虚 拟地址空间】 3、每个kmvarsdsc_t【虚拟地址空间】,都包括一个kvmemcbox_t结构【页面盒子】 4、每个kvmemcbox_t【页面盒子】,管理虚拟地址空间与物理内存页面的关系,并记录了 物理内存页面对应的 msadsc_t 结构【页面】 5、每个msadsc_t结构,是一个页面 6、为了管理方便,操作系统有一个全局kvmemcboxmgr_t结构,统一管理全部kvmemcbox_t

systick 设备中断回调函数

对于 systick 设备来说,重要的并不是打开、关闭,读写等操作,而是 systick 设备产生的中 断,以及在中断回调函数中执行的操作,即周期性的执行系统中的某些动作,比如更新系统时 间,比如控制一个进程占用 CPU 的运行时间等,这些操作都需要在 systick 设备中断回调函 数中执行。 按照前面的设计,systick 设备每秒钟产生 1000 次中断,那么 1 秒钟就会调用 1000 次这个 中断回调函数,这里我们只要写出这个函数就行了,因为安装中断回调函数的思路

我们在每个进程中都要主动调用进程调度器函数,否则进程就会永远霸占 CPU,永远运行下 去。这是因为,我们没有定时器可以周期性地检查进程运行了多长时间,如果进程的运行时间 超过了,就应该强制调度,让别的进程开始运行 drvstus_t systick_handle(uint_t ift_nr, void *devp, void *sframe) { krlthd_inc_tick(krlsched_retn_currthread());//更新当前进程的tick return DFCOKSTUS; } krlsched_retn_currthread 函数是 返回当前正在运行进程的指针。在 krlthd_inc_tick 函数中对进程的 tick 值加 1,如果大于 20 (也就是 20 毫秒)就重新置 0,并进行调度

二层到四层都是在 Linux 内核里面处理的,应用层例如浏览器、Nginx、Tomcat 都是用户态的。内核里面对于网络包的处理是不区分应用的。 从四层再往上,就需要区分网络包发给哪个应用。在传输层的 TCP 和 UDP 协议里面,都有端口的概念,不同的应用监听不同的端口。例如,服务端 Nginx 监听 80、Tomcat 监听 8080;再如客户端浏览器监听一个随机端口,FTP 客户端监听另外一个随机端口。

应用层和内核互通的机制,就是通过 Socket 系统调用。所以经常有人会问,Socket 属于哪一层,其实它哪一层都不属于,它属于操作系统的概念,而非网络协议分层的概念。只不过操作系统选择对于网络协议的实现模式是,二到四层的处理代码在内核里面,七层的处理代码让应用自己去做,两者需要跨内核态和用户态通信,就需要一个系统调用完成这个衔接,这就是 Socket。 socket 函数用于创建一个 socket 的文件描述符,唯一标识一个 socket。我们把它叫作文件描述符,因为在内核中,我们会创建类似文件系统的数据结构,并且后续的操作都有用到它。

socket 函数有三个参数。

 domain:表示使用什么 IP 层协议。AF_INET 表示 IPv4,AF_INET6 表示 IPv6。
 type:表示 socket 类型。SOCK_STREAM,顾名思义就是 TCP 面向流的,SOCK_DGRAM 就是 UDP 面向数据报的,SOCK_RAW 可以直接操作 IP 层,或者非 TCP 和 UDP 的协议。例如 ICMP。
 protocol 表示的协议,包括 IPPROTO_TCP、IPPTOTO_UDP。

通信结束后,我们还要像关闭文件一样,关闭 socket。 这里还需要交待一个可能有些人并没有想清楚的问题:epoll == 非阻塞socket?

其实并不是,首先,socket只是众多描述符中的一种,还有很多非阻塞IO都可以通过epoll来实现。另外,非阻塞socket的实现方式也不单单是epoll和socket,其实socket本身的recv函数就自带一个参数来控制是阻塞还是非阻塞状态方式接收。

管程模型

系统领域里管程模型

什么是管程 管程,英文名是 Monitor ,因此有的时候会被翻译为监视器。其实你也许很早就接触到这个概念了,比如 synchronized 关键字,很多文章就介绍过其原理是使用了监视器,只是你那个时候还并不知道监视器和管程,其实是一回事。

管程 (英语:Monitors,也称为监视器) 是一种程序结构,结构内的多个子程序(对象或模块)形成的多个工作线程互斥访问共享资源。

管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。

我的理解是:我们通过管程管理 Java 中的类,使得类是线程安全的。

管程:指的是管理共享变量以及对共享变量的操作过程,让他们支持并发。(管理类的成员变量和成员方法,让这个类是线程安全的)

Java参考了MESA模型,语言内置的管程(Synchronized)对MESA模型进行了精简。MESA模型中,条件变量可以有多个,Java内置的管程里条件变量只有一个。

Hasen模型、Hoare模型与MESA模型的一个核心区别是:当条件满足后,如何通知相关的线程?

管程要求同一时刻只允许一个线程执行,当线程T2的操作使线程T1等待的条件满足时,T1和T2怎么执行?

Hasen模型:要求notify()的代码放在代码最后,T2通知完T1后,T2结束,T1执行,这样保证同一时刻只有一个线程在执行。

Hoare模型:T2通知完T1后,T2阻塞,T1马上执行;等T1执行完,再唤醒T2,保证同一时刻只有一个线程在执行。但是多了一次阻塞唤醒操作。

MESA模型:T2通知完T1后,T2继续执行,T1并不立刻执行,仅仅是从条件变量的等待队列进入到入口等待队列里面。好处是notify()不用放到代码最后,T2也没有多余的阻塞唤醒操作。副作用是当T1再次执行时,可能曾经满足的条件,现在已经不满足了,所以需要以循环方式检验条件变量。

部分内容参考原文链接:https://blog.csdn.net/yqq962464/article/details/112267907 另一部分参考《即刻时间》(趣谈操作系统)部分内容