十二、线程介绍

进程是资源管理的最小单位,那么每个进程 都拥有自己的数据段、代码段和堆栈段。 这必然就造成了进程在进行切换时都需要有比较复杂的上下文切换等动作,因为要保存当前进程上下文的内容, 还要恢复另一个进程的上下文,如果是经常切换进程的话,这样子的开销就过于庞大,因为在进程切换上下文时, 需要重新映射虚拟地址空间、进出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)

大家都在看

  • 【Redis】WRONGTYPE Operation against a key holding the wrong kind of value

    此异常的出现情况之一:第一次为 key 设置 value 值是字符串类型,第二次 为 相同 key 设置 value 值的类型不同。 posted @2022-09-28 20:5…

    Java 2023年6月15日
    087
  • Python基础

    1.为什么学习Python 2.Python和其他语言的区别 从三个方面看Python 语言特点 语言类型 第三方库 3.Python的优势 4.Python的解释器种类? 5.p…

    Java 2023年6月7日
    082
  • Redis的中并发问题的解决方案小结

    什么是Redis的并发竞争问题 Redis的并发竞争问题,主要是发生在并发写竞争。考虑到redis没有像db中的sql语句,update val = val + 10 where …

    Java 2023年6月9日
    081
  • 22.1.30 位运算

    22.1.30 位运算 1))哈希函数可以把数据按照种类均匀分流; 2)布隆过滤器用于集合的建立与查询,并可以节省大量空间; 3)一致性哈希解决数据服务器的负载管理问题; 4)利用…

    Java 2023年6月13日
    082
  • 面试准备 — 大数据Hive相关

    1、拉链表 好文 需要查看一件事物从开始到现在的全部状态,比如用户从注册到今天改了几次手机号? 实际应用场景:1、用户数据量很大 2、某些字段经常被更新,其他字段基本不变 3、需求…

    Java 2023年6月7日
    087
  • 字符串数组与字符串指针的区别

    字符指针变量和字符数组的区别: 简单说一下: 字符串数组是用来存放字符串的数组,在内存中占一段连续的单元。所占内存存放的是字符串。定义方法为:char a[N];N为常量表达式,可…

    Java 2023年6月9日
    075
  • mybatis 字段类型映射一览表

    Original: https://www.cnblogs.com/tangzeqi/p/13155854.htmlAuthor: instrTitle: mybatis 字段类型…

    Java 2023年6月6日
    082
  • 对象到底是怎么new出来的

    前言:要想理解本文,必须先了解JVM的内存结构 一.创建对象的方式 new:最常见 反射:Class.newInstance() 使用clone() 反序列化 二.创建对象的步骤(…

    Java 2023年6月7日
    094
  • Spring @ResponseBody 返回中文乱码问题

    今天在使用spring 的时候,发现中文返回的是乱码。 经过研究发现,主要是@ResponseBody 引起的。主要是由于 @ResponseBody 返回字符串结果的时候,使用了…

    Java 2023年5月30日
    073
  • 【Java面试】准备跳槽!那这期面试题必须要会,请描述一下Redis的缓存淘汰策略

    “请你描述一下Redis的缓存淘汰策略”你如果你正好遇到这个问题,想好怎么回答了吗?关于这个问题,我把高手的回答整理到了15W字的面试文档里面大家可以私信留…

    Java 2023年6月16日
    085
  • 白盒安全测试系列 之 概述

    1.1 前言Java Web安全测试主要分为黑盒测试和白盒测试,黑盒测试是指测试人员不清楚Web具体的架构和实现,通过模拟一个或者多个攻击角色进行渗透攻击,来发现潜在的漏洞和安全风…

    Java 2023年6月7日
    0102
  • Tomcat源码分析(二)Bootstrap启动类分析

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

    Java 2023年6月5日
    086
  • MySQL索引相关

    索引相当于一本书的目录,通过目录可以快速地对应相对的资源。在数据库方面,查询一张表的时候有两种检索方式: 全表扫描 根据索引检索(效率很高) 索引虽然可以提高检索的效率,但是在决定…

    Java 2023年6月8日
    096
  • winform子线程修改界面控件的值

    示例代码 //代理:是应用程序向OS申请执行的一个函数;这里只给出了函数的"形" delegate void delSetText(TextBox txt, s…

    Java 2023年5月30日
    080
  • java.lang.NoSuchMethodError: org.springframework.util.Assert.notNull(Ljava/lang/Object;Ljava/util/function/Supplier;)V

    java.lang.NoSuchMethodError: org.springframework.util.Assert.notNull(Ljava/lang/Object;Lja…

    Java 2023年5月29日
    099
  • Docker网络[6]

    推荐: 狂神说Java Docker学习 1. 理解Docker 0 清空所有网络 测试 运行一个tomcat $ docker run -d –name tomcat01 to…

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