char *str = "hello bfr";
*str = "H";
"hello bfr"这个字符串存储在虚拟地址空间的代码区中,令str指向它之后当要修改*str时,也就是修改代码区中"hello bfr"位置的值,再将它通过页表映射成物理内存时再根据页表中的RWX权限判断出这块内存是只读的没有写权限,就会硬件报错 段错误,操作系统识别硬件报错转化成信号发送给进程,进程就会终止。
如何看待地址空间和页表:
1.地址空间是进程能看到的资源窗口
2.页表决定,进程真正拥有资源的情况
3.合理的对地址空间+页表进行资源划分,我们就可以对一个进程的所有资源进行分类。
虚拟地址如何转化成物理地址?
虚拟地址以 10 10 12位转化的;0000000000 0000000000 000000000000
页表中第一页叫做页目录(前10个比特位),有2^10个条目,直接O(1)查找匹配的页表,在拿第二个10位去所在页表中查找(2^10条目),页表中所在条目写的是指定页框的起始地址,虚拟地址的低12位作为页内偏移,再根据数据类型的大小连续向后读取字节数。没有用到的页表就不会创建,,解决内存不足问题。
物理内存被操作系统分块管理起来,用一个数组struct Page mom[ ]数组管理,每一个内存块是一个struct Page{ }的结构体。每一个块的大小是4kb。磁盘在编译时就是被划分成4kb的数据块-页帧,文件系统级别是需要将数据以4kb为单位从外设搬到物理内存。操作系统要管理内存,除了需要数据结构,还需要管理算法-伙伴系统(对某种结构做管理)。所有的算法都要匹配结构。
什么是进程?
进程 = 内核数据结构+进程对应的代码和数据。如何看待我们之前学习进程时,对应的进程概念呢?内核视角:承担分配系统资源的基本实体。一个进程内部可以有多个执行流。CPU中调度的PCB可能是进程内的一个分支(线程),凡是喂给CPU的都是轻量级进程(task_sruct),因为在CPU眼中这个PCB就是进程中创建出来的一个执行流。哪怕这个进程只有一个线程,因为在Linux中一个完整的进程包括它多个PCB和虚拟地址空间、页表、所占用的内存资源。
线程:进程内的一个执行流
如何看待虚拟内存:虚拟内存里面决定了进程能够看到的“资源”。
一个进程的资源是可以通过虚拟地址空间+页表来将自己的部分资源划分给特定线程。Linux当中创建进程的时候可以直接fork将PCB、地址空间、页表全部复制一份,还要和父进程进行解耦,因为进程具有独立性;还有一种方式通过地址空间+页表的方式对进程进行资源划分,只需要创建PCB,将新创建的pcb指向父进程的地址空间,让"子进程"能够指向父进程代码块中的一部分,资源简单划分,划分之后有多个执行流,执行力度一定比之前的进程要细。CPU调度的时候只关注task_struct,
如何实现线程
Windows:TCB线程控制块,线程在进程内部,一个PCB中还有一张链表,将这个进程内的所有线程连接起来。这样会增加线程和进程的耦合程度。
Linux:一个线程被创建的根本目的是被执行(id,状态,优先级,上下文,栈...),单纯从线程调度角度,线程和进程有很多地方是重叠的。不用给线程专门设计数据结构,直接复用PCB来表示Linux内部的“线程”。线程经常在我们的进程的地址空间内运行,只拥有该进程的一部分资源。CPU调度的基本单位。执行代码和数据。Linux使用PCB来模拟进程的,是完全属于自己的方案—可靠、高效、维护成本低。进程用来整体申请资源,线程用来伸手向进程要资源。Linux中没有真正意义的线程,无法直接提供创建线程的方法,只能提供创建轻量级进程的接口。
一个进程内要并行进行很多个任务,CPU可以高频切换执行流使多线程并行处理。
线程创建pthread_create
1.既不是语言提供的也不是操作系统提供的,用户和线程间,用户级线程库;pthread-任意Linux都要携带该库,原生线程库。g++ -o $@ $^ -lpthread
2.这些线程都属于一个进程,所以PID一致,为了区分,它们都有自己的LWD。
3.在库中输出的tid和在系统中输出的tid完全不同,与操作系统内部实现和库原理有关
4.全局变量和全局方法可以被每个线程使用;如果全局变量被一个线程改变,其它线程会立马看见
5.面试题:线程一旦被创建,几乎所有的资源都是所有线程共享的!线程也一定要有自己私有的资源,什么资源应该是线程私有的呢?
独立的PCB属性,独立的上下文结构-线程动态切换的属性,独立的栈结构-保存私有数据。ebp栈底,exb栈顶。栈区只有一个,怎么保证每个线程独立的栈结构?
6.线程间切换相较于进程间切换系统的操作要少很多
进程间切换要切换页表,页表项在寄存器中、也要进行PCB切换、要进行上下文切换、切换虚拟地址空间-PCB中的地址;线程间切换只需要切换PCB和上下文。
cache,CPU内部的硬件级缓存,和内存一样同样有数据保存功能。当前计算机的局部性原理,CPU和寄存器要访问的数据是放在CPU中的cache中每次去读取的,cache中在CPU运行时会保存很多热点数据—经常被命中,线程共享热点数据缓存,而进程切换这些数据就被清空。
补充:计算密集型(CPU:加密、解密、算法等), I/O密集型(外设:磁盘、网络、显示器,抖音)
7.多线程的缺点:
性能损失,nCPU和n核最好和进程数和线程数对应。CPU内有运算器和控制器,核指的是一个CPU内部集合了多个运算器。
健壮性降低:一个进程挂掉了不会影响另一个进程,一个线程出问题有可能会影响其他进程
缺乏访问控制:进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。