Linux 多线程原理深剖

目录

传统艺能??

小编是双非本科大二菜鸟不赘述,欢迎米娜桑来指点江山哦
在这里插入图片描述
1319365055

???非科班转码社区诚邀您入驻???
小伙伴们,满怀希望,所向披靡,打码一路向北
一个人的单打独斗不如一群人的砥砺前行
这是和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我


在这里插入图片描述

Linux 线程??

在一个程序里的一个执行路线就叫做 线程,准确的定义是 线程是一个进程内部的控制序列 color{red} {线程是一个进程内部的控制序列} 线程是一个进程内部的控制序列

首先一切进程至少都有一个执行线程。线程在进程内部运行,本质是在进程地址空间内运行。在 Linux 中,CPU 看到的 P C B color{red} {PCB} PCB 要比传统的进程更轻量化。透过进程虚拟地址空间可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了 线程执行流 color{red} {线程执行流 } 线程执行流

需要明确的是,一个进程的创建实际上伴随着其进程控制块(task_struct)、进程地址空间(mm_struct)以及页表的创建:
在这里插入图片描述
每个进程都有自己独立的进程地址空间和页表,这代表着运行本身就具有独立性。

但是我们在创建进程时,创建 task_struct ,并要求只创建 task_struct 和父 task_struct 的共享地址空间和页表:

在这里插入图片描述

以上动作其实就是在执行四个线程:每一个线程都是当前进程的一个执行流,也就是我们理解的 “执行分支” color{red} {“执行分支” } “执行分支”,这里也很容易看出,线程运行的本质就是在这个进程地址空间运行,也就是这个进程的所有资源几乎是所有线程共享的。

单纯从技术角度,这是一定能实现的,因为线程粒度比进程更小,所以它比创建原始进程更轻松。

那么再来重新理解一下之前的进程概念:

在这里插入图片描述
因此,进程不仅通过task_struct来衡量,还要有进程地址空间、文件、信号等等,这些合起来称为一个进程,从内核角度来看 进程就是系统资源分配的基本单位 color{red} {进程就是系统资源分配的基本单位 } 进程就是系统资源分配的基本单位,直白的说就是我们是创建一个 task_struct 并且创建进程地址空间,维护页表,然后再物理内存中开辟空间,映射地址,打开相关文件和注册信号对应的解决方案等等

而我们之前接触到的进程都只有一个 task_struct,也就是该进程内部只有一个执行流,即单执行流进程,反之,内部有多个执行流的进程叫做多执行流进程

那么问题来了:CPU 是否识别当前调度的 task_struct 是进程还是线程

No!答案是不能,而且也不需要,CPU 只会关心一个独立的执行流,无论进程内部是一个还是多个执行流,CPU 都是以 task_struct 为单位进行来调度的,不妨对比一下单执行流和多执行流:

单执行流:
在这里插入图片描述
多执行流:
在这里插入图片描述
这就是就是我们所说的CPU看到的还是 task_struct ,只是更加轻量化。

但是!Linux 里并不存在真正的多线程,他的多线程是用进程模拟的

操作系统中存在大量的进程,一个进程内又存在多个线程,因此线程的数量一定远超进程。如果一个操作系统要真正的支持线程,就必定有某种结构对线程进程管理,比如线程的创建,终止,转换,调度和释放回收等等,为什么说 Linux 是神?Linux 相比另起炉灶去创建一套线程管理体系,他选择直接就地取材用进程搭建一条平行的线程管理机制

其实这就是一个复用的思想,因此在 Linux 看来线程的控制块和进程的控制块是类似的,他并没有单独搞出一个数据结构来描述他,而是直接对进程取而用之,这也是为什么我们将所有进程·的执行流都叫做轻量化进程,Windows 是支持线程操作的,这也是为什么windows操作系统逻辑比 Linux 复杂的多

既然在 Linux 没有真正意义的线程,那也绝对没有线程相关的系统调用!

但是 Linux 提供了创建轻量级进程的接口,其中最典型的代表就是 vfork 函数,函数功能是创建子进程,并且父子共享空间:

pid_t vfork(void);

vfork 返回值与 fork 一样,父进程返回子进程的 PID,子进程返回 0,比如下面代码中父进程使用 vfork 创建子进程,子进程修改了全局变量 g_val,父进程休眠 3 秒后会读取到全局变量 g_val 的值证明父子进程共享地址空间:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int g_val = 100;
int main()
{
	pid_t id = vfork();
	if (id == 0){
		//child
		g_val = 200;
		printf("child:PID:%d, PPID:%d, g_val:%d
", getpid(), getppid(), g_val);
		exit(0);
	}
	//father
	sleep(3);
	printf("father:PID:%d, PPID:%d, g_val:%d
", getpid(), getppid(), g_val);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值