当前位置: 首页 > news >正文

个人做网站 优帮云成都最新热门事件

个人做网站 优帮云,成都最新热门事件,企业网站建设好的案例,微信的在线客服系统欢迎来到博主专栏:从0开始linux 博主ID:代码小豪 文章目录 进程与线程线程概念线程的优点线程的独立数据 进程与线程 如果要理解线程,那么进程将会时绕不开的点。首先我们回顾一下我们之前在进程章节当中是如何描述进程的? 进程&…

欢迎来到博主专栏:从0开始linux
博主ID:代码小豪

文章目录

    • 进程与线程
    • 线程概念
    • 线程的优点
    • 线程的独立数据

进程与线程

如果要理解线程,那么进程将会时绕不开的点。首先我们回顾一下我们之前在进程章节当中是如何描述进程的?

进程=内核数据结构+代码和数据

代码和数据很好理解,我们在c/c++文件当中写的代码和数据,经过编译后形成的二进制可执行程序中,数据和指令都已二进制的形式保存在文件中。而内核数据结构指的是PCB(task_struct),mm_struct,vm_area_struct(进程地址空间),还有页表等等。这些存在于内核当中,描述与管理进程的相关数据结构。

那么线程是什么呢?

这里博主先从其中一个概念开始展开:线程是进程中的一个执行流,是进程的执行分支。

那么问题来了,什么是执行流呢?

我们可以将流看做是进程中连续的cpu指令,cpu在执行这些指令流,就叫做执行流。而根据进程地址空间,我们的cpu执行的指令、数据的地址,都是保存在进程地址空间当中的,而线程相当于是将这个进程地址空间的一部分切割开来,作为自己的地址空间,让cpu从中处理。那么此时进程就分为了两个执行流,继续执行主程序的,叫做主线程,而执行分支程序的,就是分支线程。

在这里插入图片描述

多说无益,我们尝试创建一个线程,创建线程用到的是C语言posix库中的函数pthread_create,关于这posix库是什么,我们在下一篇章节再说,pthread_create的函数原型如下:

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

这些参数博主先不多介绍,首先start_routine是一个函数指针,即分支线程开始的函数地址(我们可以看成是线程的main函数)。pthread_t是线程号,线程号我们后面再说。我们只需要传入一个pthread_t的参数的地址即可。

那么程序如下:

void* Thread1Run(void* addr)//分支线程的入口函数
{while(true){std::cout<<"hello 我是线程1"<<std::endl;sleep(1);}
}int main()
{pthread_t tid;//创建分支线程pthread_create(&tid,nullptr,Thread1Run,(void*)"thread-1");while(true){std::cout<<"hello 我是主线程"<<std::endl;sleep(1);}return 0;
}

这段程序的逻辑如下:当进程运行时,此时内部没有分支线程,当执行pthread_create后,创建出一个分支线程。该线程执行Thread1Run函数的逻辑。此时进程1内部就出现了两个执行流,主执行流继续执行主函数的代码,而分支线程执行Thread1Run的代码。

运行结果如下:
在这里插入图片描述
从这里可以看出,主线程和分支线程是并行的,如果不是并行的,那么主线程压根不会执行pthread_create中的代码。

线程概念

如果线程可以并行,那么一定是需要linux系统对线程进行调度的,就像进程调度那样。那么既然linux要对线程管理起来,linux是如何管理线程的呢?老生常谈,linux管理进程,是通过创建内核数据结构,描述进程,接着通过内核数据结构来进行管理,我们将这个操作称为:先描述,再组织

那么线程又要如何描述呢?我们先来思考这么一个问题:我们需要线程有什么?首先,线程要有描述符,这样操作系统才能通过描述符找到要操作的线程;接着,线程要有执行的代码和数据,因此要有自己的地址空间;线程也可以通信、因此还要有文件描述符表fd_array。线程还要能接收到信号,因此要有pending表、block表、handler表。咦,这么看下来线程的内核数据结构好像和进程的内核数据结构一模一样啊?

没错,线程和进程用的内核数据都是一样的,即task_struct!!!!

这么一搞、我们就要对一个问题进行思考了。线程是什么?进程又是什么?

首先博主为进程和线程先下一个定义:线程是操作系统调度的最小单位、进程是承载分配资源的基本实体。

在我们上一个例子中已经看到,cpu会在线程之间进行切换调度,其原理和进程之间的切换调度类似。那么如何理解进程时承载分配资源的基本实体呢?首先我们来思考,一个进程需要什么资源?

首先进程要有地址空间吧,代码、数据、堆区、栈区,这些都是实打实存在于内存当中的,第二个,进程会打开文件吧,这些文件都也是要加载到内存当中的。这些就叫做资源。

那么线程有没有这些呢?答案是有!但是为什么说进程承载资源,而不是线程承载资源呢?这是因为,由线程申请的资源,都是放到进程名下的!如何理解这句话呢?我们在前面不是说了吗?将进程空间的一部分代码、数据分割给分支线程,线程就创建出来了,那么我们逆推一下:进程=主线程+分支线程

我们之前所见过的进程,是不是没有线程呢?非也,而是这些进程当中只有一个主线程,因此,我们在前面所说的进程调度,本质上也是线程调度,只是这个线程只存在一个而已。那么现在我们知道了,线程申请的一切资源都是放在进程名下的,这也意味着,线程之间使用的资源都是共享的即,同一进程下的线程使用的地址空间是相同的,使用的文件描述表也是相同的!!那么理解了这个,对于线程和进程的关系就很明了了。

我们可以以现实举个例子,比如我们从寝室走到教室,那么我们这个人就是一个进程,执行的任务就是到达教室,而我们的左脚、右脚、左腿、右腿则是进程下的线程,各自执行自己的程序,但是目的都是为了完成一个进程的任务。这些线程所使用的资源是共享的,即人体身上的能量,你总不能说你的左腿运动和右腿运动消耗的能量不属于同一个人吧?

在linux中,线程和进程其实并没有太大的区别,因此在linux当中,线程被称为轻量级进程,又称LWP(light weight process)。所谓的cpu对进程的调度,无论是进程还是轻量级进程,它们的权重没有任何区别。而且我们还能查到轻量级进程的属性,通过指令:ps -aL可以查看,但是考虑到让轻量级进程与进程之间有所区别,因此后面还是叫线程和进程。
在这里插入图片描述

线程的优点

  • 创建⼀个新线程的代价要比创建⼀个新进程小得多

我们fork出一个新进程,由于进程之前具有独立性,因此新进程要有自己的地址空间,要有自己的内核数据结构。而线程之间都是共享进程的资源的,因此创建一个新线程,只需要创建一个新的内核数据结构来描述轻量级进程就行。

  • 线程之间切换比进程之间切换的速度快

为什么呢?因为进程之间具有独立性,不同的进程,其代码数据不同,使用的进程地址空间也不同,页表不同,打开的文件也不同,这些东西都是要实打实加载到内存的。要加载,就是要让磁盘与内存之间做慢速I/O,因此速度变慢。

而且在CPU当中也有体现,不同的进程,其上下文也是不一样的,并不是说线程的上下文就相同,而是进程的上下文更复杂。因为在CPU当中存在两个东西,一个叫做TLB,一个叫做cache。这两个硬件都是用来做缓存的。TLB负责的是页表缓存,不同的进程拥有不同的页表,因此TLB肯定不能复用,因此切换进程的时候,TLB要重新作缓存,而线程之间由于使用的是相同的进程空间,因此在切换线程的时候,TLB就不用更新。

而cache我们还没认识过,现在我们就来讲讲。当一个进程运行时,我们要将进程中的数据和代码加载到内存当中,因为cpu与内存之间做交互的速度远快于cpu与磁盘做交互,但是cpu和内存之间的交互是最快的吗?当然不是,而是cpu与cache之间的交互才是最快的,因此,当cpu执行一个代码时,会将代码附近的所有数据都加载到cache当中,我们可以输入指令cat /proc/cpuinfo可以查看到cpu信息,其中就包括cache的大小
在这里插入图片描述

我们可以看到,一个cached可以缓存40M左右的数据,因此当cpu执行一个指令时,首先会查该指令的地址是否在cache当中,如果没有,再去内存当中找,顺便在将cache当中缓存的数据更新成,新执行的指令附近40M的数据。

那么为什么说cache能提高效率呢?这其实是一个概率性的问题,因为当计算机执行完一个代码后,其第二条代码,大概率在该代码的下一条。因此将代码附近的数据加载到cache中,可以大大减少cpu访问内存的次数。但是如果你能写出让cpu访问的代码不停跳转的程序,那么这个cache就相当于是负优化了,因为cache不仅没有让你减少cpu访问内存的频率,还要不停地加载内存中的数据到cache当中,这个时间只会更长。因此,这个基于cache缓存以提高cpu效率的方法,我们称为局部性原理。因此我们所写的代码和数据,要尽可能的减少不必要的跳转,以提升程序的运行速度。

那么我们回到进程,由于进程使用的内存空间是不同的,因此cache缓存的数据,是基本不可能让两个进程一起用的。因此切换进程的时候,cache当中的数据也要更新一下,这不也导致了cpu效率变慢了吗?而线程之间由于使用的资源都是在一个进程当中的,因此cache缓存大概率不用更新,因此切换线程所需要的时间开销也会变小。

但是线程并非完全没有缺点。

• 性能损失
◦ ⼀个很少被外部事件阻塞的计算密集型线程往往⽆法与其它线程共享同⼀个处理器。如果计
算密集型线程的数量⽐可⽤的处理器多,那么可能会有较⼤的性能损失,这⾥的性能损失指
的是增加了额外的同步和调度开销,⽽可⽤的资源不变。
• 健壮性降低
◦ 编写多线程需要更全⾯更深⼊的考虑,在⼀个多线程程序⾥,因时间分配上的细微偏差或者
因共享了不该共享的变量⽽造成不良影响的可能性是很⼤的,换句话说线程之间是缺乏保护
的。
• 缺乏访问控制
◦ 进程是访问控制的基本粒度,在⼀个线程中调⽤某些OS函数会对整个进程造成影响。

这里我们做简单的了解,博主在后面的章节当中还会继续说明

线程的独立数据

进程当中有哪些资源是线程之间共享的?而线程之间又有什么资源是不互通的?

共享的资源有:

  • 进程地址空间
  • 信号:所有线程对于信号的处理方式,都是一致的
  • 异常:如果一个线程出现了异常,那么整个进程都会崩溃
    其实这也很好理解,比如广西周某偷了电瓶,总不能说是我的手偷的,而不是总体偷的,进而免除惩罚吧?由于线程作为进程的一部分,所有的线程的目的,都是为了让进程完成某个任务,因此如果一个线程出现了异常,那么进程的任务还能完成吗?因此将进程中所有线程一起处理,才是正确的处理方法。
  • 文件描述符

不共享的资源有:

  • LWP:线程ID
  • 信号屏蔽字:即block表,虽然线程之间对待信号的处理方法一致,但是线程可以选择屏蔽掉啊
  • 线程的上下文数据:虽然使用的资源是相同的,但是它们具体执行的指令可不同,因此cpu在切换线程时,它们的上下文数据也要进行切换(只是切换线程的复杂度远低于切换进程。)
  • errno
  • 调度优先级
http://www.shuangfujiaoyu.com/news/20374.html

相关文章:

  • 做视频网站流量费高吗外包公司是正规公司吗
  • 画册设计制作广东seo推广外包
  • 专门做朋友圈小视频的网站百度网页游戏中心
  • 企事业网站建设网络推广是做什么的
  • 携程网网站是哪家公司做的免费推广平台有哪些
  • 六安哪家公司做网站好著名的营销成功的案例
  • 房产证查询系统官方网站网站运营主要做什么
  • wordpress网站图片加速广州网络推广外包平台
  • 做网站需要数据库短视频seo营销
  • 自适应网站怎么做全部视频支持代表手机浏览器
  • 网站上滚动海报怎么做的站长工具高清吗
  • 网站用哪些系统做的比较好营销推广48个方法
  • 新北区城乡建设局网站市场调研报告1500字
  • 大连网站制作学校医院营销策略的具体方法
  • 北京市建设工程信息网站郑州seo技术外包
  • 嘉兴外贸网站制作免费b2b推广网站大全
  • 中企动力的网站如何qq群排名优化软件购买
  • 企业网站推广哪些效果比较好网络营销专业是干什么的
  • 优质网站建设方案旅游推广赚佣金哪个平台好
  • 学校网站 asp爱站网关键词怎么挖掘
  • 百度搜索网站怎么做当日网站收录查询统计
  • 西安外贸网站开发重庆人社培训网
  • 支持快钱支付的网站百度服务中心投诉
  • 沧州网站建设专业的公司4000-262-重庆seo海洋qq
  • 深圳开发网站开发百度手机助手网页
  • 中国未来巨型空间站东莞seo外包
  • 西宁最好的建站公司今天热点新闻
  • 什么做网站做个网站一般要多少钱啊广告类的网站
  • 成都开发微信小程序seo1域名查询
  • 网络文化经营许可证变更法人站长工具seo综合查询引流