进程与线程的区别——源码级别

一、线程与进程的区别

前天面试的时候被问到了进程与线程的区别,本来这种面试题想来也没有什么好说的我也就没太在乎,结果他问的时候我就支支吾吾的说了他们关于资源开销,空间管理,进程通信三个方面的情况,其实有这三个就够了,重要的是要能够展开说才可以,比如说讲到独享内存你就要说到他们的安全性,调试的方便性,以及他们的从属关系。其实说白了上面这些都是围绕着进程独占内存,线程共享内存来展开的,接下来来详细看看他们源码级别的区别吧!

二、进程的创建

fork其实个人已经剖析过一次了,在前面内存管理的章节,它主要就是做两件事,即复制父进程的task_struct结构与唤醒创建的进程。

1.复制进程task_struct总结
  • 分配task_struct
  • 创建内核栈,设置task_struct->stack变量
  • 复制task_struct,底层调用memcpy实现,即复制虚拟空间
  • 设置内核栈的thread_info
  • 进行权限相关的设置,如谁可以操作我,我可以操作谁等
  • 进行调度相关统计量的初始化,与调度类,调度优先级的设定
  • 复制文件描述符数组相关数据结构与进程文件系统目录信息。
  • 复制信号相关的数据结构,如各种信号处理函数的入口等
  • 复制父进程内存空间管理相关数据结构
  • 最后分配进程ID,设置tid和group_leader.
2.唤醒子进程
  • 首先设置子进程状态为运行态
  • 接下来将该进程挂在CPU相关的调度类的调度队列上,尝试进行抢占式调度
  • 抢占式调度上一篇文章《进程的主动调度与抢占式调度》已经讲过,在唤醒子进程的这个函数中他就会尝试去进行一次唤醒,若可以发生抢占式调度就设置相关变量等待时机进行抢占。
  • 别忘了,fork是一个系统调用,当我们从内核态返回用户态的时候就会尝试进行进程的调度。
3.小总结

通过以上的简单介绍起码知道,创建一个进程要做什么事情,也知道了为什么fork系统调用无法确认两个进程的执行顺序,以及何时发生调度,怎样发生抢占,这个和上一讲有了一个稍微密切的联系。

三、线程的创建

简单来说,线程创建(也即pthread_create)是用户态和内核态的结合,首先它会在主线程(当前进程)的堆区为新创建的线程创建用户态的栈,之后会调用clone系统调用(底层还是fork调用的那些函数,只不过参数不一样)引用一些主线程的数据结构,注意是加一个引用,类似C++的智能指针那样,最后当从系统调用返回的时候就会调用我们设置的用户态线程函数。

四、线程与进程源码级别的区别
  • 进程是资源分配的最小单位,线程是CPU调度的最小单位
  • 进程独占内存空间,线程共享内存空间
    个人认为其实区别就是上面的两点,网上好多所谓的区别其实大都是第二条派生出来的,我们看到第二条其实就应该可以立刻想到诸如线程安全性,通信的便利性,线程死亡的安全性,系统资源开销问题以及所谓的从属关系。
    来瞅一瞅,由上面对线程创建的简单介绍之后我们应当知道,它会在调用clone系统调用的时候是直接引用计数的,故它在创建和销毁也就方便的多了,不像进程一样要逐项复制文件系统、内存管理等一些臭大臭大的数据结构,所以它的系统开销也会小很多,同时正是由于这种共享关系的存在,假设我们某个线程出了问题了收到了致命信号,那么就相当于是所有的线程都收到了,故我们常说一个线程死了那么整个进程就死了,至于从属关系其实还是由task_struct结构体来设计完成的,通信的便利性就更不用说了,就线程的栈是在进程的堆区创建这一个性,就可以发现每一个线程的数据(自然包括主线程)都会被其他线程所共享,当然线程的局部数据是不允许共享的,但线程的私有数据可以呀!所以这样通过层层分析我们就可以发现对于内核来说哪儿来的进程和线程,他们只不过都是一个个CPU调度实体而已,在内核是拥有相同的地位。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值