图解linux32位平台下进程线程长什么样子

0.linux的进程线程

程序是某种格式的可执行文件,是和os相匹配的。比如windows下的程序是exe格式的可执行文件,unix下的程序是elf可执行文件。具体些,就是比如linux下main.c里只写了一个main函数,gcc main.c编译输出的elf格式的可执行文件a.out。那么,a.out就是程序。
线程是程序的一个执行流。 这个怎么理解?执行流? 程序里面可以包含很多线程,线程其实就是程序中的函数,有的是无限循环,有的是开环顺序执行完就退出了,有的是有条件的循环函数。 每个线程函数都被编译器编译成一堆对应架构的指令集的指令。程序是一堆指令的集合——而这一堆指令里包含了一个个线程函数的执行指令。所以说“线程是程序的一个执行序列”——执行序列就是指的是线程函数的执行指令,它只是程序中的一部分。
进程是程序的实例化。程序相当于类,进程相当于对象。说的就是面向对象中的类的实例化。什么是实例化?就是创建一个对象。创建一个对象又是什么?就是实例化。哈哈,循环了。但其实创建对象就是类的实例化,类的实例化就是开辟一个内存块。 同理,程序的实例化 就是将可执行文件加载到内存中并可被CPU执行。 比如在windows下,你双击某个exe格式的文件xxx,比如在unix和类unix下,你在shell中执行某个elf格式的文件——敲命令./xxx。这两种行为导致的结果就是:激活OS内核可执行文件加载器把可执行文件xxx加载到内存,然后为它开辟进程地址空间,再把进程栈、线程栈等资源准备好,然后跳入到main函数去执行(主线程),在main函数中创建了很多线程。程序就这样运行起来了。当然你可以重复实例化同一个可执行程序,即可以打开多个一模一样功能的进程。比如你可以在windows下登陆2个qq——双击一次qq登陆一个账号,再双击一次qq再登陆另一个小号。这运行的2个qq是2个进程,但是同一个程序——同一个可执行文件qq——它在内存中实例化了2个对象。unix类似。

但linux不区分进程线程的,都是task_struct
数据结构的角度看:
linux进程是一个task_struct或一组task_struct的集合。
linux线程是一个task_struct。

1.单线程的进程

单线程的进程
单线程的进程就是只有一个main函数且main函数里面没有调用glibc/uclibc等运行时库的pthread_create接口去创建线程。

由上图可以看到:
(1)主线程栈(也叫进程栈)是在栈区的。主线程栈是向下增长的,是满递减栈。 栈区最大是8MB,这是个内核宏,可设。主线程栈是在8MB内,唯一一个可以访问未映射区而不会段错误的一个地址空间。
(2)mm指向进程地址空间(每个进程的地址空间是唯一的,所以表示它的内存描述符指向的结构体内存块也是唯一的,是为单例模式 )。单进程单线程相当于一个独门独院,一个人独享风景,很爽啊!
(3)主线程一般是main函数——因为c/c++规定一个程序只能有一个main函数。
(4)pid是线程号,tgid(thread group id线程组ID,可见linux对进程的解释就是线程组 )是进程号。主线程的pid和tgid是相等的。
(5)group_leader指向主线程,即自己。

2.多线程的进程

多线程的进程
多线程的进程就是只有一个main函数,但在main函数里面调用了glibc/uclibc等运行时库的pthread_create接口创建了很多很多线程。

可以看到:
(1)主线程栈(也叫进程栈)是在栈区的。主线程栈是向下增长的,是满递减栈。 栈区最大是8MB,这是个内核宏,可设。主线程栈是在8MB内,唯一一个可以访问未映射区而不会段错误的一个地址空间。
(2)普通线程栈是在mmap区的,每个线程栈是8MB+4KB的大小,其中4KB是隔离区域,线程栈不是向下生长的,只是后进先出LIFO的数据结构。
(3)主线程一般是main函数——因为c/c++规定一个程序只能有一个main函数。
(4)pid是线程号,tgid是进程号。主线程的pid和tgid是相等的,其他线程的pid号和tgid是不同的。注意:ps命令看到的PID是task结构体里的tgid,即进程号,LWP才是线程号pid。 不要奇怪,我猜这可能是历史原因,因为早期是没有支持线程的,后来支持线程了,怎么表示线程进程号?只好用pid来表示线程号了,增加tgid表示进程号吧!
(5)group_leader指向主线程。你看所有普通线程的group_leader都指向主线程。
(6)mm指向进程地址空间(每个进程的地址空间是唯一的,所以表示它的内存描述符指向的结构体内存块也是唯一的,是为单例模式)。主线程创建时会开垦这个地盘,其他线程直接领包入住。好有一比,主线程就是党打下了江山,而普通线程就是这个江山的子民——别人问你是你哪国人?你说你是中国人。那自然主线程开辟的领土地盘就是你活动的地盘。多个线程就好比多个人都是中国人,进程地址空间就相当于中国的地理版图。

3 总结
3.1 公共之处

(1)主线程栈(也叫进程栈)是在栈区的。主线程栈是向下生长的,是个满递减栈。栈区最大是8MB,这是个内核宏,可设。主线程栈是在8MB内,唯一一个可以访问未映射区而不会出现段错误的一个特殊空间地址。
(2)mm指向进程地址空间。好有一比,这个线程你属于哪个国家的?多个线程就好比多个人都是中国人,进程地址空间就相当于中国的地理版图。mm还用来区分是进程切换还是线程间切换。可参见相关博客。
(3)主线程一般是main函数——因为c/c++规定一个程序只能有一个main函数。
(4)pid是线程号,tgid是进程号。主线程的pid和tgid是相等的。
(5)group_leader指向主线程。你看所有普通线程的group_leader都指向主线程。

3.2 差异之处

(1)栈的差异。多线程的进程比单线程的进程多了其他的普通线程和普通线程栈。主线程栈在栈区,向下生长。普通线程栈在mmap区,一般是由glibc/uclibc等运行时库调用mmap开辟的8MB+4KB大小的区域,不是向下生长,只是后进先出的数据结构,应该也可以理解成向下生长吧,这块还得搜索相关资料,深入理解。
(2)

4.好的图解文章推荐
4.1 深入理解linux内核中的栈

深入理解linux内核中的栈
我喜欢的是它把linux的task_struct结构体的mm成员指向的mm_struct内存块与进程地址空间的映射图给画出来了!太棒了!截图如下:
很棒的task与进程地址空间映射图

4.2 进程虚拟内存管理

进程虚拟内存管理
这个画的又丰富了些。如下截图:
进程虚拟内存管理

4.3基础知识系列

cpu与mmu
讲的非常棒的图,截图如下:
在这里插入图片描述在这里插入图片描述

linux c 虚拟地址转真实地址
很不错,截图如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值