线程-概念理解

线程-概念理解 学Linux线程涉及一些概念的理解正好输出倒逼输入拿写博客的方式来“用自己的话讲解线程”。一提到线程本身按照自己的思考逻辑来说会产生下列问题。如果没有线程仅仅只有进程能满足实际的开发需求吗线程的意义线程和进程二者的区别在哪里一定是因为线程有什么独特的优势才会在进程的基础上生长出线程。线程作为一个抽象的概念它在代码上的具体体现是什么谁在管理线程又是通过什么抓手来管理线程的接下来尝试以这样的逻辑轮流回答它们。并发与线程——如果只有进程不论物理硬件和软件算法如何发展作为开发者都必定逃不开一个问题资源有限而需求无限。如果有限的资源我们都通过进程来执行任务。进程的基本特征是彼此之间共享内核空间但是用户空间是独立、隔离的。没有线程的话每个进程一次只做一件事情。假设这么一个场景我要下载一部电影下载的同时我想去上网打发打发时间。可是如果只有进程一次只做一件事情那么当你开始下载电影的时候CPU的全部资源都用来下载电影了已经没有其余的资源让你做其他的事情。你只能等电影下载完才能去做其他的事情。“做完一件事才会去做另一件事”这就是串行的概念。从上面的场景描述显而易见只有进程、CPU串行的情况下无法满足多任务的需求。有没有一种方式能够让我一边下载电影一边打游戏或者干其他的事情呢于是前辈们就引入了并发和线程。包括后面的协程也都是为了满足并发场景的需求。并发是什么为了避免出现“视频下载完之前啥事也干不成”的串行悲剧就有人想到“欸就不能多几个干活的吗”于是CPU从单核发展到了多核每个核心都能执行任务。为了再多提高一下执行效率就引入了并发。当出现多个任务要执行时操作系统就把线性的时间切分为一小段一小段的时间片让CPU在每个时间片内执行一项任务时间片一到就切换到其他任务。由于CPU的运算速度是远超于人的反应的所以在宏观层面上CPU就能同时处理多个任务并行不悖。但微观层面上CPU依然是串行执行的逻辑。既然涉及到任务的切换CPU和操作系统如何保证下次能回到当时暂停的地方呢假如有2个任务A和B。一个时间片里CPU执行任务A从0到60%下一个时间片里CPU切换到任务B从20%到36%再下一个时间片CPU切换回任务A它能找到任务A在60%的地方吗这就涉及到上下文的切换。当时间片到期时CPU会把当前任务的栈帧、变量等数据保存起来接着加载下一个任务的位置如此来保证每次都能在对的位置继续执行。线程和进程的关系——优劣对比进程是资源分配单位线程是CPU调度单位。但其实CPU调度单位容易让人认为线程是由CPU管理的。但实际上管理线程的是操作系统OS它来决定线程的使用权而CPU则单纯负责执行线程中的指令。关于进程它的核心之一就是虚拟地址空间。每一个进程都会有操作系统给它们分配独立的地址空间。挖坑进程的虚拟地址空间分区单开一篇说明。进程的地址空间先大致分为两个部分——用户区和内核区前者是用来存放函数栈帧、变量等相关数据的地方后者则是跟操作系统内核相关。进程之间用户区互相隔离内核区则是共享的。如果把每个进程看作一颗颗大树那么土地之上的枝叶就是用户区彼此独立而土地之下的根茎是内核区共享的是同一片大地。那么线程会在哪个位置呢线程位于土地之上即进程的用户区。一个进程可以创建多个线程它们共享的都是进程的地址空间。不过线程依然有专属于自己的部分寄存器上下文、栈、线程ID。这个后面会再次说明。也可能不会毕竟贱人多忘事。线程的优点就在于它的上下文切换开销小速度快所以适合并发的场景。相比之下进程的上下文切换就显得笨重。经典的hello world程序在运行过程中进程和线程做了什么hello world程序启动操作系统创建进程——创建第一个线程——线程开始执行程序入口——调用main()函数。此时在进程A的地址空间中就有了线程1的栈空间。这个线程在Linux中通常叫做main threadWindows系统中则叫做primary thread。线程会运行_start()——libc初始化libc_start_main——进入main()所以操作系统并不知道什么是main()函数它只知道线程。线程的数据结构线程和进程一样信息都存在PCB(Process Control Block)进程控制块里对应的是task_struct结构体。线程操作——线程如何被管理线程由操作系统来管理。Linux提供了一系列的与线程有关的函数构成了POSIX线程库。引入pthread.h头文件就能使用线程控制的相关函数了。有关于线程的主要操作有5个线程创建资源回收线程结束线程等待线程分离