只买域名不建网站,湖北中英双语网站建设,国家免费培训学校,阿里云的wordpress建站目录
一、细粒度划分
1、堆区细粒度划分
2、物理内存和可执行程序细粒度划分
3、虚拟地址到物理地址的转化
二、线程的概念
1、基本概念
2、线程的优点
3、线程的缺点
4、线程异常
5、线程用途
三、Linux下的进程和线程 一、细粒度划分
1、堆区细粒度划分
在语言…目录
一、细粒度划分
1、堆区细粒度划分
2、物理内存和可执行程序细粒度划分
3、虚拟地址到物理地址的转化
二、线程的概念
1、基本概念
2、线程的优点
3、线程的缺点
4、线程异常
5、线程用途
三、Linux下的进程和线程 一、细粒度划分
1、堆区细粒度划分
在语言中我们知道用户自己申请的空间是存在于地址空间的堆区上的。可是堆区是一整块空间我们每次申请只是申请了其中的一小块并且我们只是说明了申请空间的大小拿到的是空间的起始地址。如果我们多次申请了空间那么我们怎么知道第一次申请的空间是从堆区哪里到哪里呢第二次申请的空间是从堆区哪里到哪里呢
于是os就必须对堆区进行更加精细的管理。在Linux下每次从堆区申请一块空间os就会创建结构体 struct vm_area_struct 该结构体中的数据就是用户申请的每一块空间的相关属性其中就有空间的起始位置和结束位置。os对于用户申请的空间的管理就成了对结构体链表的管理。os通过这样的精细划分能够更好地管理用户申请的每一块空间。
当然链表的整个范围也一定是在堆区的范围之间的。 上图就是os对堆区的细粒度划分的大概内容。
2、物理内存和可执行程序细粒度划分
根据下图我们来说明。
首先我们需要知道1、a.exe这个可执行程序是一个文件。2、a.exe等可执行程序在磁盘上已经按地址空间的方式编译好了。3、并且a.exe等可执行程序已经被分成了若干个4KB大小的小块我们称之为页帧。
当a.exe刚开始运行一个进程刚开始运行的时候os首先创建进程的PCB地址空间页表但是还没有通过页表建立虚拟地址到物理地址的联系而是通过某种硬件方式直接让地址空间找到磁盘上的可执行程序。
在页表中有一列的数据表示是否在内存中下图页表绿色的部分。当执行具体的代码时进程必定会通过页表访问物理内存。检测页表时发现数据不在内存中于是地址空间不再直接与磁盘上的可执行程序建立联系os将a.exe加载到物理内存中通过页表与地址空间建立联系。这叫做缺页中断。
其实物理内存也被分成了若干个4KB大小的小空间我们称之为页框。os将a.exe加载到物理内存中的具体过程就是通过IO将4KB大小的页帧放进4KB大小的页框中。 当然对于这些若干个页框os也必须对其进行管理。每一个页框都有一个struct page结构体里面都是页框的各种属性该结构体中有一个成员flag表示该页框是否被占用。然后将这些结构体存储到一个 struct page men[ ] 数组中数组的下标就是该页框的编号。
3、虚拟地址到物理地址的转化
我们结合下图进行说明。 我们早就知道虚拟地址和物理地址之间的联系是通过页表建立的。但是真正的转化是不止通过一个页表来实现的。
我们平时所说的地址就是虚拟地址它一共有32个比特位页表是一种key,value结构的数据结构。我们通过前10个比特位找到一级页表中的key然后通过value值找到二级页表然后通过虚拟地址的第二组10个比特位找到二级页表的key值位置接着根据value值找到物理内存中某个页的起始地址。最后根据虚拟地址的最后12个比特位进行数值计算最后找到数据在该页的准确位置。
二、线程的概念
1、基本概念 1、在一个程序里的一个执行路线就叫做线程thread。更准确的定义是线程是一个进程内部的控制序列一切进程至少都有一个执行线程。 2、线程在进程内部运行本质是在进程地址空间内运行。 3、透过进程虚拟地址空间可以看到进程的大部分资源将进程资源合理分配给每个执行流就形成了线程执行流。 每个进程都有自己独立的地址空间和独立的页表也就意味着所有进程在运行时本身就具有独立性那么如果我们在创建“进程”时只创建PCB并要求新创建出来的PCB与第一次创建的PCB共享地址空间页表等资源那么就是下图的情况 每个线程都是当前进程里的一个执行流线程在进程内部运行准确来说线程在进程的地址空间内运行拥有并使用该进程的一部分资源。
所以说进程从内核的角度来说就是承担分配系统资源的基本实体因为线程都是直接从进程处拿到各种资源的。当然这与我们之前所理解的进程的概念并不矛盾我们之前的进程都只有一个PCB也就是该进程内部只有一个执行流即单执行流进程。从今天开始我们就会讲到一个进程有多个执行流即多执行流进程。
从用户的角度来说进程就是包括一个或多个PCB执行流、地址空间、页表等内核数据结构以及内存中的代码和数据。 线程是CPU调度的基本单位。 前面我们说CPU去处理一个进程的时候最先拿到的是它的PCB来决定调度谁。那么现在我们知道了准确来说CPU拿到的是一个线程因为CPU以task_struct为单位进行调度。
我们给CPU的task_struct是小于等于过去所说的task_strcut的比之前的更轻量化了Linux下的进程也叫做轻量级进程。因为每一个task_struct只管理着一个进程的一部分资源。它是进程下的一个执行流。 Linux下的线程是用进程PCB模拟的。 在Linux下设计者并没有单独为线程设计一个像进程的PCB那样的数据结构 因为线程所需要的属性和进程非常相似所以我们直接复用PCB用PCB来表示Linux内部的“线程”。但是如果os真的要专门设计“线程”概念os那就需要管理线程了先描述在组织这样就提高了os的维护成本。
Linux内核中有没有真正意义的线程Linux是用进程PCB来模拟线程的这种设计方法是Linux特有的。
2、线程的优点 1、创建一个新线程的代价要比创建一个新进程小得多。 2、与进程之间的切换相比线程之间的切换需要操作系统做的工作要少很多。 3、线程占用的资源要比进程少很多。 4、能充分利用多处理器的可并行数量。 5、在等待慢速I/O操作结束的同时程序可执行其他的计算任务。 6、计算密集型应用为了能在多处理器系统上运行将计算分解到多个线程中实现。 7、I/O密集型应用为了提高性能将I/O操作重叠。线程可以同时等待不同的I/O操作。 3、线程的缺点 1、性能损失 一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多那么可能会有较大的性能损失这里的性能损失指的是增加了额外的同步和调度开销而可用的资源不变。 2、健壮性降低 编写多线程需要更全面更深入的考虑在一个多线程程序里因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的换句话说线程之间是缺乏保护的。 3、缺乏访问控制 进程是访问控制的基本粒度在一个线程中调用某些OS函数会对整个进程造成影响。 4、编程难度提高 编写与调试一个多线程程序比单线程程序困难得多。 4、线程异常
单个线程如果出现除零野指针问题导致线程崩溃进程也会随着崩溃。线程是进程的执行分支线程出异常就类似进程出异常进而触发信号机制终止进程进程终止该进程内的所有线程也就随即退出 。
#include iostream
#include unistd.h
#include string
#include pthread.husing namespace std;void *thread_run(void *argc)
{while(true){sleep(1);int a 10;a / 0;}
}int main()
{pthread_t tid;pthread_create(tid, nullptr, thread_run, (void *)thread1);while (true){cout main thread pid: getpid() endl;sleep(3);}return 0;
}
5、线程用途
合理的使用多线程能提高CPU密集型程序的执行效率合理的使用多线程能提高IO密集型程序的用户体验如生活中我们一边写代码一边下载开发工具就是多线程运行的一种表现。
三、Linux下的进程和线程 1、进程是资源分配的基本单位。 2、线程是调度的基本单位。 3、线程共享进程数据但也拥有自己的一部分数据。 线程共享的进程资源
1、文件描述符表 2、每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数) 3、当前工作目录 4、用户id和组id
线程需要自己私有的资源
1、线程ID2、一组寄存器线程必须要有自己的上下文 3、栈独立的栈结构能够保存自己的临时变量 4、errno 5、信号屏蔽字 6、调度优先级