奔向大厂/外企系列(三)线程的模型和实现

131 阅读3分钟

前言

上一篇文章,粗略讲了进程和线程的相关概念。这一篇文章将要详细的讲一下线程的相关知识。

线程模型

进程把资源集中到一起,而线程是cpu上调度执行的实体。在同一个进程环境中,允许多个具有较大独立性的线程执行,它们共享同一个地址空间和其他资源。线程在单个cpu中是轮流执行的,也就是说当线程都是cpu密集型的时候,多线程并不能提高执行效率。

线程也具有三个状态:运行、就绪、阻塞。线程拥有自己的堆栈。

POSIX线程

Pthread_create 创建新的线程

Pthread_exit 结束调用线程

Pthread_join 等待特定线程退出

Pthread_yield 释放cup运行另外一个线程

Pthread_attr_init 创建并初始化一个线程的属性结构

Pthread_attr_destory 删除线程的属性结构

用户空间和内核空间

简单的来说,操作系统将虚拟地址分为了两部分。一部分供操作系统内核,处于顶部为内核空间。一部分位于底部为用户空间。在cpu的所有指令中,有些指令非常危险,如果用错,容易导致系统崩溃。所以cpu把指令分为特权指令和非特权指令。如intel,将cpu指令划分为ring0~ring3 四个级别。而linux只使用了ring0和ring3两个级别。当进程运行在ring0级别时,就是运行在内核态。运行在ring3就是运行在用户态。

在内核态下,进程运行在内核地址空间中,cup可以运行所有指令。在用户态下,进程运行在用户地址空间中,被执行的代码要受到 CPU 的诸多检查。

如何从用户空间进入内核空间

所有的系统资源管理都是在内核空间中完成的,我们的应用程序需要通过内核提供的接口来完成相关的任务。进程在内核态和用户态各有一个堆栈。运行在用户空间时进程使用的是用户空间中的堆栈,而运行在内核空间时,进程使用的是内核空间中的堆栈。所以说,Linux 中每个进程有两个栈,分别用于用户态和内核态。

线程的实现

线程有三种实现方式,在用户空间中实现、在内核空间中实现、混合实现。

用户空间实现

把整个线程包放在用户空间中,内核无法感知到线程包。内核调度的还是单线程进程。优点:1)可以运行在不支持线程的操作系统上。2)允许进程有自己的调度算法。缺点:1)系统阻塞调用问题。2)如何解决饥饿问题。

内核空间实现

进程不再需要运行时系统,也不需要维护线程表。在内核中有用来记录所有线程的线程表。由操作系统来调度。创建开销大。

混合实现

使用内核级线程,然后将用户级线程与某些或者全部内核线程多路复用起来。内核只识别内核级线程,并对其进行调度。其中一些内核级线程会被多个用户级线程多路复用。如同在没有多线程能力操作系统中某个进程中的用户级线程一样,可以创建、撤销和调度这些用户级线程。在这种模型中,每个内核级线程有一个可以轮流使用的用户级线程集合。