十二、线程介绍

进程是资源管理的最小单位,那么每个进程 都拥有自己的数据段、代码段和堆栈段。 这必然就造成了进程在进行切换时都需要有比较复杂的上下文切换等动作,因为要保存当前进程上下文的内容, 还要恢复另一个进程的上下文,如果是经常切换进程的话,这样子的开销就过于庞大,因为在进程切换上下文时, 需要重新映射虚拟地址空间、进出OS内核、寄存器切换,还会干扰处理器的缓存机制, 因此为了进一步减少CPU在进程切换时的额外开销,因此Linux进程演化出了另一个概念——线程。

线程是操作系统能够调度和执行的基本单位,在Linux中也被称之为轻量级进程。在Linux系统中, 一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等), 而将线程分配到某个cpu上执行。 一个进程可以拥有多个线程,它还可以同时使用多个cpu来执行各个线程 , 以达到最大程度的并行,提高工作的效率;同时,即使是在单cpu的机器上,也依然可以采用多线程模型来设计程序, 使设计更简洁、功能更完备,程序的执行效率也更高。

从上面的这些概念我们不难得出一个非常重要的结论:

线程的本质是一个进程内部的一个控制序列,它是进程里面的东西,一个进程可以拥有一个进程或者多个进程。

它们的关系就如图所示:

回顾一下进程相关的知识:

  • 当进程执行fork()函数创建一个进程时,将创建出该进程的一份新副本。 这个新进程拥有自己的变量和自己的PID,它的执行几乎完全独立于父进程,这样子得到一个新的进程开销是非常大的。
  • 而当在进程中创建一个新线程时,新的执行线程将拥有自己的栈,但与它的创建者共享全局变量、文件描述符、信号处理函数和当前目录状态。 也就是说,它只使用当前进程的资源,而不是产生当前进程的副本。
  • Linux系统中的每个进程都有独立的地址空间,一个进程崩溃后,在系统的保护模式下并不会对系统中其它进程产生影响,
  • 而线程只是一个进程内部的一个控制序列,当进程崩溃后,线程也随之崩溃,所以一个多进程的程序要比多线程的程序健壮, 但在进程切换时,耗费资源较大,效率要差一些。但在某些场合下对于一些要求同时进行并且又要共享某些变量的并发操作, 只能用线程,不能用进程。

  • 一个程序至少有一个进程,一个进程至少有一个线程。

  • 线程使用的资源是进程的资源,进程崩溃线程也随之崩溃。
  • 线程的上下文切换,要比进程更加快速,因为本质上,线程很多资源都是共享进程的,所以切换时, 需要保存和切换的项是很少的。

线程属性里包含了调度策略配置,POSIX 标准指定了三种调度策略:

  • 分时调度策略,SCHED_OTHER。这是线程属性的默认值,另外两种调度方式只能用于以超级用户权限运行的进程, 因为它们都具备实时调度的功能,但在行为上略有区别。
  • 优先级调度策略,先进先出方式调度(SCHED_FIFO)。基于队列的调度程序,对于每个优先级都会使用不同的队列, 先进入队列的线程能优先得到运行,线程会一直占用CPU,直到有更高优先级任务到达或自己主动放弃CPU使用权。
  • 时间片轮转调度策略 ,时间片轮转方式调度(SCHED_RR)。与 FIFO相似,不同的是前者的每个线程都有一个执行时间配额, 当采用SHCED_RR策略的线程的时间片用完,系统将重新分配时间片, 并将该线程置于就绪队列尾,并且切换线程,放在队列尾保证了所有具有相同优先级的RR线程的调度公平。

与调度相关的API接口如下:

若函数调用成功返回0,否则返回对应的错误代码。

参数说明:

  • attr:指向一个线程属性的指针。
  • inheritsched:线程是否继承调度属性,可选值分别为
  • PTHREAD_INHERIT_SCHED:调度属性将继承于创建的线程,attr中设置的调度属性将被忽略。
  • PTHREAD_EXPLICIT_SCHED:调度属性将被设置为attr中指定的属性值。
  • policy:可选值为线程的三种调度策略,SCHED_OTHER、SCHED_FIFO、SCHED_RR。

线程栈是非常重要的资源,它可以存放函数形参、局部变量、线程切换现场寄存器等数据, 在前文我们也说过了,线程使用的是进程的内存空间,那么一个进程有n个线程,默认的线程栈大小是1M, 那么就有可能导致进程的内存空间是不够的,因此在有多线程的情况下,我们可以适当减小某些线程栈的大小, 防止进程的内存空间不足,而某些线程可能需要完成很大量的工作,或者线程调用的函数会分配很大的局部变量, 亦或是函数调用层次很深时,需要的栈空间可能会很大,那么也可以增大线程栈的大小。

设置、获取线程栈大小可以使用以下函数:

参数说明:

  • attr:指向一个线程属性的指针。
  • stacksize:线程栈的大小。

代码的分析如下:

  • 第8~16行,定义test_thread函数作为线程要执行的函数,函数内部的操作是打印传入的arg参数, 然后睡眠一定的时间,最后调用thread_exit退出线程。
  • 第29行,调用pthread_create函数创建线程,传入的线程函数指针为test_thread, 并且传入了一个函数参数arg(520),创建后线程将会开始执行test_thread的代码。
  • 第40行,创建线程后调用 pthread_join等待线程退出。

要注意的是,本示例中需要在Makefile中添加lpthread链接库的内容:

Original: https://www.cnblogs.com/yuanqiangfei/p/16202109.html
Author: 轻轻的吻
Title: 十二、线程介绍

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541970/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 设计模式 — AbstractFactory(抽象工厂)

    抽象工厂(Abstract Factory) 提供一个接口,让该接口负责创建一系列”性关系或相互依赖的对象”,无需指定他们的具体类。 在软件系统中,经常会面…

    Java 2023年6月16日
    093
  • Excel 使用 VLOOKUP 函数匹配特定列

    前言 工作有一项内容,是根据新的表格的某一列的内容一对一匹配,生成一列新的表格。这就用到了 Excel 的 VLOOKUP 函数。 函数使用 函数体: =VLOOKUP(looku…

    Java 2023年6月7日
    098
  • java线程池

    Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。在开发过程中,合理地使用线程池能够带来许多好处。 什么是线程池? Java中的线程…

    Java 2023年6月13日
    066
  • 【力扣】11. 盛最多水的容器

    给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i…

    Java 2023年6月8日
    073
  • java 中的原始类型与原始封装类型

    Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。比如:Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装…

    Java 2023年5月29日
    094
  • Java集合框架概述:Collection(List, Set, Queue)和Map

    http://sparkandshine.net/java-collections-framework-overview-collection-list-set-queue-map…

    Java 2023年5月29日
    070
  • Kubernetes-Service

    1. 简介 kubernets service 是将运行一组pods上的应用程序公开为网络服务的抽象方法。 有了 kubernets service,你就无需修改应用程序即可使用服…

    Java 2023年6月7日
    070
  • Java并发编程:4种线程池和缓冲队列BlockingQueue

    一. 线程池简介 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,…

    Java 2023年5月29日
    057
  • 第一个HTML

    DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-…

    Java 2023年6月5日
    070
  • quartz框架(六)-ThreadPool

    本篇博文,博主将介绍Quartz框架中ThreadPool线程池相关的内容。线程池顾名思义,就是一个可以帮助我们来进行线程资源管理的对象。在web开发中,常见的就有数据库连接池,h…

    Java 2023年6月7日
    075
  • Spring boot 2.0 之优雅停机

    spring boot 框架在生产环境使用的有一段时间了,它”约定大于配置”的特性,体现了优雅流畅的开发过程,它的部署启动方式( java -jar xxx…

    Java 2023年5月30日
    067
  • SpringBoot 整合Swagger2 踩坑记录

    SpringBoot 整合Swagger2 踩坑记录 Failed to start bean ‘documentationPluginsBootstrapper&#8…

    Java 2023年6月5日
    090
  • MyBatis 配置类详解

    核心配置文件中的标签必须按照固定的顺序: properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objec…

    Java 2023年6月7日
    062
  • Spring Boot+Mybatis 配置多数据源

    目前业界操作数据库的框架一般是 Mybatis,但在很多业务场景下,我们需要在一个工程里配置多个数据源来实现业务逻辑。在 SpringBoot中也可以实现多数据源并配合 Mybat…

    Java 2023年5月30日
    077
  • 130_RabbitMQ使用场景

    异步-同步异步问题 串行方式 并行方式 异步线程池 异步消息队列的方式 解耦-高内聚,低耦合 削峰-流量的削峰 分布式事务的可靠消费和可靠生产 索引、缓存、静态化处理的数据同步 流…

    Java 2023年6月7日
    063
  • Java基础

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月5日
    074
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球