从linux源码角度看进程、线程

什么是进程,什么是线程

       我们大家都知道,进程是运行中的程序代码以及它所使用的数据集合的总和,线程是cpu调度的基本单位,但是这都是很抽象的概念,我们要知道进程与线程是被代码实现了的客观存在,说白了我就是想问从代码上看进程、线程到底是什么,linux内核中用什么来代表一个进程呢?是一个函数吗,还是一个整型变量,亦或是一个结构体?
       其实,对于linux内核来说,是没有进程和线程的区别的,它们都是由一个叫做task_struct的结构体表示的,该结构体定义在include\linux\sched.h中,在我使用的4.1版本的内核中,该结构体已经长达435行了,它是内核用来描述一个进程信息的结钩体,也叫做PCB(进程控制块)。里面一些重要成员的意思可以看大佬的文章

https://kernel.blog.csdn.net/article/details/51383272

进程和线程的区别

       既然说二者在内核看来都是task_struct结构体,那么二者的区别在哪呢?在内核中不论是进程还是线程都是通过clone系统调用实现的,创建进程的实现是clone(SIGCHLD, 0);而创建线程时则是clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND, 0);可以看出二者的区别只是在于参数标志不同,clone函数有很多的参数标志,定义在include\uapi\linux\sched.h中。
       拿其中最主要的CLONE_VM举例,clone函数会调用do_fork()函数,do_fork()函数中又使用copy_process()函数来完成task_struct结构体的拷贝。copy_process()函数中又会调用copy_mm()函数来完成mm成员的分配(struct mm_struct *mm,该结构体表示进程的虚拟地址空间,在上面那个链接中有介绍)。这里来看看copy_mm的部分源码

oldmm = current->mm; //current是一个内核定义的宏,它是当前进程的task_struct的指针
if (clone_flags & CLONE_VM) {
		atomic_inc(&oldmm->mm_users);
		mm = oldmm;
		goto good_mm;
	}

       可以看出当clone_flags设置为CLONE_VM时,新创建的task_struct的mm指针等于当前进程的mm指针,就是说线程的mm指针和创建它的进程的mm指针指向的是同一个虚拟地址空间,也因此线程间可以共享全局变量、静态全局变量。那么问题又来了,我们知道线程是有自己独立的用户栈的,但是按刚刚说的mm指针指向同一个虚拟地址空间,那它们不就是共用同一个栈吗?在linux命令行中输入man clone,看它的参数,参数列表中最为显眼的就是第二个参数void *child_stack,man里面是这样形容它的:
       The child_stack argument specifies the location of the stack used by the child process. Since the child
and calling process may share memory, it is not possible for the child process to execute in the same stack as the calling process.
       意思是参数child_stack指定了子进程使用的堆栈的位置。由于子进程和调用进程可能共享内存,因此子进程不可能与调用进程在同一个堆栈中执行(有道翻译)。所以在调用clone函数之前,我们需要先为线程分配栈空间,在pthread_create函数源码中我们可以看到(位于glibc库的pthread_create.c文件中)它调用了ALLOCATE_STACK()函数,看名字我们就可以猜出这个函数为栈分配了空间,继续看,发现里面调用了mmap函数来申请空间。所以线程是有自己的用户栈的,不过由于使用mmap申请的,所以它的大小是固定的,而进程的栈是fork函数中拷贝父进程的,是可以生长的(也有最大限制)。

特殊的内核线程

       内核线程可以看作linux内核这个进程(其实是3号kthreadd进程)创建的线程,为了帮它完成各种各样复杂的任务,内核线程由于始终运行在内核空间,所以它没有自己的虚拟地址空间,即它的mm指针为NULL,但是有时它也要用到一些内核信息,所以task_struct中有一个成员定义为struct mm_struct *active_mmactive_mm指针指向正在使用的虚拟地址空间,对于其他进程线程而言,它的值和自己的mm相等,对于内核线程,则等于上一个运行进程线程的mm。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值