鼠扑 发表于 2024-6-22 12:59:45

Linux之线程概念

目录
一、细粒度划分
1、堆区细粒度划分
2、物理内存和可执行步调细粒度划分
3、虚拟地址到物理地址的转化
二、线程的概念
1、根本概念
2、线程的优点
3、线程的缺点
4、线程异常 
5、线程用途
三、Linux下的进程和线程

一、细粒度划分

1、堆区细粒度划分

在语言中,我们知道,用户自己申请的空间是存在于地址空间的堆区上的。可是,堆区是一整块空间,我们每次申请只是申请了其中的一小块,并且我们只是阐明了申请空间的巨细,拿到的是空间的起始地址。如果,我们多次申请了空间,那么我们怎么知道第一次申请的空间是从堆区那里到那里呢,第二次申请的空间是从堆区那里到那里呢?
于是os就必须对堆区举行更加精致的管理。在Linux下,每次从堆区申请一块空间,os就会创建结构体 struct vm_area_struct ,该结构体中的数据就是用户申请的每一块空间的相干属性,其中就有空间的起始位置和结束位置。os对于用户申请的空间的管理就成了对结构体链表的管理。os通过这样的精致划分,能够更好地管理用户申请的每一块空间。
固然,链表的整个范围也一定是在堆区的范围之间的。
https://img-blog.csdnimg.cn/direct/a5727d46e03e4a77bf4f969f2bd0e222.png
上图就是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巨细的页框中。
https://img-blog.csdnimg.cn/direct/f84b3849f0ea4eb680b16534444de479.png
固然,对于这些若干个页框,os也必须对其举行管理。每一个页框都有一个struct page结构体,里面都是页框的各种属性,该结构体中有一个成员flag,表现该页框是否被占用。然后将这些结构体存储到一个 struct page men[ ] 数组中,数组的下标就是该页框的编号。 
3、虚拟地址到物理地址的转化

我们结合下图举行阐明。
https://img-blog.csdnimg.cn/direct/9080707b024e44069e9cdaf54c071a74.png
我们早就知道虚拟地址和物理地址之间的接洽是通过页表建立的。但是,真正的转化是不止通过一个页表来实现的。
我们平常所说的地址就是虚拟地址,它一共有32个比特位,页表是一种key,value结构的数据结构。我们通过前10个比特位找到一级页表中的key,然后通过value值找到二级页表,然后通过虚拟地址的第二组10个比特位,找到二级页表的key值位置,接着根据value值找到物理内存中某个页的起始地址。最后,根据虚拟地址的最后12个比特位,举行数值计算,最后找到数据在该页的准确位置。
二、线程的概念

1、根本概念

   1、在一个步调里的一个执行门路就叫做线程(thread)。更准确的界说是:线程是一个进程内部的控制序列,统统进程至少都有一个执行线程。
2、线程在进程内部运行,本质是在进程地址空间内运行。
3、透过进程虚拟地址空间,可以看到进程的大部门资源,将进程资源合理分配给每个执行流,就形成了线程执行流。
每个进程都有自己独立的地址空间和独立的页表,也就意味着全部进程在运行时自己就具有独立性那么如果我们在创建“进程”时,只创建PCB,并要求新创建出来的PCB与第一次创建的PCB共享地址空间,页表等资源,那么就是下图的环境:
https://img-blog.csdnimg.cn/direct/7678cc282a644c8f8ad3c46890af40c4.png
每个线程都是当进步程里的一个执行流,线程在进程内部运行,准确来说线程在进程的地址空间内运行,拥有并使用该进程的一部门资源。 
以是说,进程从内核的角度来说就是负担分配系统资源的根本实体,因为线程都是直接从进程处拿到各种资源的。固然,这与我们之前所明白的进程的概念并不矛盾,我们之前的进程都只有一个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.h>

using 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;
} https://img-blog.csdnimg.cn/direct/589c86a59f5841fca69165a271e1a84d.png​​​​​​​ 
5、线程用途

合理的使用多线程,能提高CPU密集型步调的执行效率合理的使用多线程,能提高IO密集型步调的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现)。
三、Linux下的进程和线程

   1、进程是资源分配的根本单位。
2、线程是调度的根本单位。
3、线程共享进程数据,但也拥有自己的一部门数据。
线程共享的进程资源:
1、文件形貌符表
2、每种信号的处置惩罚方式(SIG_ IGN、SIG_ DFL或者自界说的信号处置惩罚函数)
3、当前工作目录
4、用户id和组id
线程必要自己私有的资源:
1、线程ID
2、一组寄存器(线程必须要有自己的上下文)
3、栈(独立的栈结构,能够生存自己的临时变量)
4、errno
5、信号屏蔽字
6、调度优先级

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Linux之线程概念