对线程的一些理解

什么是线程?

线程和进程的关系是属于关系,线程属于进程,一个进程中可以同时存在多个线程,多个线程共享进程的内存地址空间,共享堆、文件等,独占栈和寄存器

引入线程之后,CPU的调度单位就从进程变为了线程,不过进程仍是资源分配的基本单位。

为什么引入线程?
只有在多任务的场景下才需要线程,单任务就一个进程即可,多任务的场景下频繁切换进程开销大,而多个线程之间共享进程的资源,所以线程切换的开销比进程切换小,所以引入线程节省开销

相应的代价就是:

  • 当进程中的一个线程崩溃时,会导致其同一进程中的所有线程都崩溃。
  • 多线程使得父子进程的继承更加复杂,子进程是继承父进程的所有线程还是单个线程呢,实际情况下会很复杂,容易导致错误。

线程的特点:
在这里插入图片描述

线程间的同步方式

进程之间是资源隔离的,所以需要进程通信保证互斥和同步
而线程之间共享资源,无需通信,但是为了保证资源使用的正确性,需要同步机制。

常用的线程间同步方式有:
1、互斥锁(mutex)
2、条件变量(condition)

互斥锁可以单独使用,条件变量必须配合互斥锁一起使用。

互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。

而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起配合使用。

使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。

多进程 vs 多线程

综合对比
在这里插入图片描述
如何选择?
大多数情况下都是优先使用多线程,无论IO密集型还是cpu密集型。多线程的性能开销都更小

优先使用多进程的情况也有,因为一个线程崩溃时,同一进程下的多个线程都会崩溃,而进程之间不影响。
比如大多数浏览器就是采用的多进程,多进程架构的好处:可以保证安全性、可靠性和对浏览器如何使用资源的可问责性。

1、增强的安全性
如果恶意软件利用了一个渲染器进程中的安全漏洞,则很难逃脱该进程并影响另一个进程。

渲染器进程是最有可能受到攻击的进程,因为它是与网站交互的进程。该进程的特权较低,并且对操作系统的访问受到极大限制,因此,如果恶意软件控制该进程,则它将无法控制该计算机。渲染器进程和浏览器进程之间的通信范围狭窄且受到保护,恶意软件很难利用此优势来利用浏览器进程。

另外,进程隔离可以防止一个进程访问另一个进程的内存,这也提高了浏览器的安全性。举例来说,假设您正在网上购买衬衫,并且该网站上有一个广告。您所访问的网站需要访问您的信用卡信息才能完成交易;但是,广告不需要访问此信息。广告将按照自己的流程进行处理,因此即使广告遭到入侵,也无法轻松访问您的敏感信息。

2、可靠性
如果网页、Web应用、扩展程序或插件发生崩溃,只有正在崩溃的进程才会受到影响,提高浏览器的可靠性。浏览器的其余部分,包括大多数其他选项卡,将保持稳定。

3、资源问责制
隔离每个进程,可以更容易地在任务管理器中看到哪个进程使用了最多的资源,并提供有关哪些资源使用的信息。Microsoft Edge使用最多的资源,还是网站,扩展程序或插件?您还可以在Microsoft Edge的内部任务管理器中看到这些信息,您可以在Microsoft Edge中按Shift+Esc键打开,或者进入浏览器的上角,选择设置和更多(…)>更多工具>浏览器任务管理器。
浏览器多进程原文

用户态线程 vs 内核态线程

左图为在用户空间实现的线程,右图为在内核空间实现的线程
在这里插入图片描述

内核态线程 vs 用户态线程
内核态线程由内核创建,受操作系统调度器直接管理
而用户态线程则是应用自己创建的,内核不可见,因此也不受系统调度器管理。
与内核态线程相比,用户态线程更加轻量级,创建开销更小,但功能也较为受限,与内核态相关的操作(如系统调用)需要内核态线程协助才能完成。

在用户空间实现线程

用户线程在用户空间中实现,内核对其一无所知
在用户空间管理线程时, 每个进程需要有其专用的线程表( thread table), 用来跟踪该进程中的线程。 这些表和内核中的进程表类似, 不过它仅仅记录各个钱程的属性, 如每个线程的程序计数器、堆栈、指针、 寄存器和状态等。该线程表由运行时系统管理。当一个钱程转换到就绪状态或阻塞状态时,在该线程表中存放重新启动该线程所需的信息,与内核在进程表中存放进程的信息完全一样。

当某个线程做了一些会引起在本地阻塞的事情之后,例如,等待进程中另一个线程完成某项工作,它调用一个运行时系统的过程,这个过程检查该线程是否必须进入阻塞状态。如果是,它在线程表中保存该线程的寄存器(即它本身的),查看表中可运行的就绪钱程,并把新线程的保存值重新装入机器的寄存器中。只要堆枝指针和程序计数器一被切换,新的线程就又自动投入运行。如果机器有一条保存所有寄存器的指令和另一条装入全部寄存器的指令,那么整个钱程的切换可以在几条指令内完成。进行类似于这样的线程切换至少比陷入内核要快一个数量级(或许更多),这是使用用户级线程包的极大的优点。

优点:
1、可以在不支持线程的操作系统中实现
2、用户线程之间的切换不需要陷入内核,不需要切换上下文,也不需要对高速缓存和内存进行刷新,所以相对内核线程的开销小,速度快。
3、用户线程有更好的可扩展性,因为内核线程需要固定的堆栈空间,而用户线程不是,所以更加灵活。

缺点:
如果一个线程开始运行, 那么在该进程中的其他线程就不能运行,除非第一个线程自动放弃CPU. 在一个单独的进程内部,没有时钟中断,所以不可能用轮转调度(轮流)的方式调度线程。除非某个线程能够按照自己的意志进入运行时系统,否则调度程序就没有任何机会。
对线程永久运行问题的一个可能的解决方案是让运行时系统请求每秒一次的时钟信号(中断),但 是这样对程序也是生硬和无序的。 不可能总是高频率地发生周期性的时钟中断,即使可能,总的开销也是很大的。而且,线程可能也需要时钟中断,这就会扰乱运行时系统使用的时钟。

在内核空间实现线程

如上面右图所示,在内核空间实现线程就不再需要运行时系统了,每个进程也没有线程表,线程表和进程表一样都在内核空间中。

和用户线程对比:
1、内核线程中,当一个线程阻塞时,内核根据其选择,可以运行同进程中的其他线程或者其他进程的线程
而用户级线程中,运行时系统始终运行自己进程中的线程,直到内核剥夺其cpu为止。

2、内核中的线程创建销毁开销比较大,所以在线程被销毁时,内核会采用伪销毁的方式销毁线程,即只是标记这个线程不可执行,线程的内核数据结构不受影响,在创建新线程时重新使用这个伪销毁的线程。节约开销
而用户级线程的开销本来就很小,所以没有必要这样做。

混合实现

人们已经研究了各种试图将用户级线程的优点和内核级线程的优点结合起来的方佳。一种方也是使用内核级线程,然后将用户级线程与某些或者全部内核线程多路复用起来,如图2-17所示。如果采用这种方式,编程人员可以决定有多少个内核级线程和多少个用户级线程彼此多路复用。这一模型带来最大的灵活度。

采用这种方式,内核只识别内核级线程,并对其进行调度。其中一些内核级线程会被多个用户级线程多路复用。如同在没有多线程能力操作系统中某个进程中的用户级线程一样,可以创建撤销和调度这些用户级线程。

多线程模型

为了实现用户态线程与内核态线程的协作,操作系统会建立两类线程之间的关系,这种关系称为多线程模型
一般来说,多线程模型主要有三种:多对一模型、一对一模型、多对多模型,下图展示了它们的结构:
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值