Linux--线程概念+线程控制

news2025/1/23 13:04:48

1.什么是线程

相对于进程而言,进程是承担资源调度的实体,线程在进程内部运行,是操作系统调度的基本单位。

在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列。

一切进程至少都有一个执行线程。
线程在进程内部运行,本质是在进程地址空间内运行。
在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化。
透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流。

从上图中可以说明,cpu在调度的时候是不知道它调度的是线程还是进程的。

如果我们在创建“进程”时,只创建task_struct,并要求创建出来的task_struct和父task_struct共享进程地址空间和页表,那么创建的结果就是上面这样的。

现在创建的进程不再给你独立分配地址空间和页表,而是都指向同一块地址空间,共享同一块页表。所以这四个task_struct看到的资源都是一样的,我们后续可以通过某种方式把代码区拆分成4块,让这四个task_struct执行不同的代码区域,上述的区域(数据区,堆区,栈区)也是类似处理方式。换言之,我们后续创建的3个task_struct都各自有自己的一小份代码和数据,我们把这样的一份task_struct称之为线程。对于Linux下的进程来说,Linux其实并没有真正的对线程创建对应的数据结构。

因此:

        线程本身是在进程内部运行的,操作系统中存在大量的进程,一个进程内又存在一个或多个线程,因此线程的数量一定比进程的数量多(线程 : 进程 一定是n : 1),当线程的数量足够多的时候,很明显线程的执行粒度要比进程更细。
        对于这么多的线程我们OS需要对其做管理(先描述,再组织),在大部分的OS中,线程都有一个tcb。如果我们的系统实现的是真线程,比如说windows平台,它就要分别对进程和线程设计各自的描述的数据块(结构体),并且很多线程在一个进程内部,所以还要维护线程tcb和进程pcb之间的关系。所以这样写出的代码,其tcb和pcb两个数据结构之间的耦合度非常复杂。设计tcb和pcb的人认为这样的进程和线程在执行流层面上是不一样的。但是Linux不这样想:在概念上没有进程和线程的区分,只有一个叫做执行流。Linux的线程是用进程PCB模拟的。所以在Linux当中,其PCB和TCB是一回事!!!

Linux的线程用进程PCB模拟的好处很明显:

  1. 不用单独设计tcb了(Linux认为tcb和pcb的属性上很大部分重叠了,不需要单独设计pcb)。
  2. 不用维护tcb和pcb之间的关系了。
  3. 不用在编写任何调度算法了。

线程的优点:

  1. 创建一个新线程的代价要比创建一个新进程小得多
  2. 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
  3. 线程占用的资源要比进程少很多
  4. 能充分利用多处理器的可并行数量
  5. 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
  6. 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
  7. I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作
     

线程的缺点:

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

一个进程内部一定存在多个执行流,问:这些执行流在CPU的角度有区别吗?

答案是没有任何区别,CPU调度的时候照样以task_struct为单位来进行调度,这里只是task_struct背后的代码和页表只是曾经的代码和页表的一小部分而已。所以CPU执行的只是一小块代码和数据,但并不妨碍CPU执行其它执行流。所以我们就可以把原本串行的所有代码而转变成并发或并行的让这些代码在同一时间点得以推进。总结如下:以前CPU看到的所有的task_struct都是一个进程,现在CPU看到的所有的task_struct都是一个执行流(线程)

Linux下进程再理解:

有了这些知识后,我们对线程的认识也发生了改变,之前的理解是:进程==操作系统所对应的代码和数据结构和进程本身所对应的代码和数据结构。

现在的理解:

现在的进程,站在内核角度上看就是:承担分配系统资源的基本实体(进程的基座属性)。所有进程最大的意义是向系统申请资源的基本单位。因此,所谓的进程并不是通过task_struct来衡量的,除了task_struct之外,一个进程还要有进程地址空间、文件、信号等等,合起来称之为一个进程。换言之,当我们创建进程时是创建一个task_struct、创建地址空间、维护页表,然后在物理内存当中开辟空间、构建映射,打开进程默认打开的相关文件、注册信号对应的处理方案等等。

所以,在Linux系统下,Linux是没有真正的线程的,只是通过将进程通过封装,模拟出的一个线程,所以在Linux下的PCB结构体中是小于等于其他平台的PCB的概念。

线程是操作系统调度的基本单位。

Linux下没有真正意义上的线程,那么也就绝对没有真正意义上的线程相关的系统调用。这很好理解,既然在Linux中都没有真正意义上的线程了,那么自然也没有真正意义上的线程相关的系统调用了。但是Linux可以提供创建轻量级进程的接口,也就是创建进程,共享空间。

2.进程控制

原生线程库pthread

在Linux系统中,是没有原生的线程库的,因此系统为用户层提供了原生线程库pthread。

pthread库:

  • 原生线程库实际就是对轻量级进程的系统调用进行了封装,在用户层模拟实现了一套线程相关的接口。
  • 因此对于我们来讲,在Linux下学习线程实际上就是学习在用户层模拟实现的这一套接口,而并非操作系统的接口。

下面来看下线程库提供的函数接口:

创建线程:pthread_creater()

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

参数:pthread_t 线程地址,attr用于创建现成的属性,通常为NULL,void* 为回调函数,为创建线程的实现方法,args为传给现成的参数。

返回值:成功返回0,失败返回error

注意:Linux不能真正意义上的帮我们提供线程的接口,但是Linux有原生线程库,使用此函数必须在编译时带上 -pthread 选项。

获取线程IP:pthread_self()

没有参数

返回值:成功返回线程地址,失败返回error.

线程等待:pthread_join()
#include <pthread.h>
pthread_join(pthread_t thread,void** retval)

参数:thread 线程id名,线程返回值,通常为空。

返回值:成功返回0,错误返回error

线程终止:pthread_exit()

#include <pthread.h>
pthread_exit(void*retval);

参数:返回值

返回值:成功退出当前线程,失败返回error

线程取消:pthread_cancel()

#include <pthread.h>
pthread_cancel(pthread_t thread);

参数:被取消线程id。

返回值:成功取消线程,返回值为0,错误返回error

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1209890.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android模拟器的linux内核源码的下载

文章目录 Android模拟器的linux内核源码的下载 Android模拟器的linux内核源码的下载 git clone https://aosp.tuna.tsinghua.edu.cn/android/kernel/goldfish.git自己新建一个文件夹存放内核代码&#xff0c;命名随意。 切换一下分支就有东西了 切换到下面这个分支

【Python】Numpy(学习笔记)

一、Numpy概述 1、Numpy Numpy&#xff08;Numerical Python&#xff09;是一个开源的Python科学计算库&#xff0c;用于快速处理任意维度的数组。 Numpy使用ndarray对象来处理多维数组&#xff0c;该对象是一个快速而灵活的大数据容器&#xff0c; Numpy num - numerical 数…

Javaweb之javascript事件案例的详细解析

1.6.4 案例 1.6.4.1 需求说明 接下来我们通过案例来加强所学js知识点的掌握。 需求如下3个&#xff1a; 点击 “点亮”按钮 点亮灯泡&#xff0c;点击“熄灭”按钮 熄灭灯泡 输入框鼠标聚焦后&#xff0c;展示小写&#xff1b;鼠标离焦后&#xff0c;展示大写。 点击 “全…

c语言从入门到实战——基于指针的数组与指针数组

基于指针的数组与指针数组 前言1. 数组名的理解2. 使用指针访问数组3. 一维数组传参的本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组 前言 指针的数组是指数组中的元素都是指针类型&#xff0c;它们指向某种数据类型的变量。 1. 数组名的理解 我们在使用指针…

Maya动画怎么云渲染?如何避免渲染出错?100%解决方案在这!

1.为什么Maya要使用云渲染&#xff1f; Autodesk Maya是一款3D动画和视觉效果软件&#xff0c;在影视、游戏和广告等各个领域中得到了广泛应用。许多知名的动画制作公司和工作室都使用Maya来制作角色动画和特效。然而&#xff0c;随着视觉效果的不断提升&#xff0c;渲染工作量…

Word软件手动安装Zotero插件

文章目录 Word软件手动安装Zotero插件方法一方法二 参考资料 Word软件手动安装Zotero插件 方法一 关闭word在zotero中依次点击编辑—首选项—引用—文字编辑软件—重新安装加载项Microsoft word 方法二 寻找Zotero.dotm存储位置&#xff0c; 例如D:\Program Files\Zotero\ext…

接口自动化测试,必须要掌握post提交数据的这4种方式

我们都知道POST一般用于向服务端提交数据&#xff0c;POST提交数据的4种格式即Content-Type的4种形式&#xff0c;尤其注意每种格式中http发送请求时body中数据的格式。4种形式分别是&#xff1a; 一、application/x-www-form-urlencoded&#xff1a;URL encoded。 二、multi…

Android设计模式--工厂模式

一&#xff0c;定义 工厂模式与Android 设计模式--单例模式-CSDN博客&#xff0c;Android设计模式--Builder建造者模式-CSDN博客&#xff0c;Android设计模式--原型模式-CSDN博客 一样&#xff0c;都是创建型设计模式。 工厂模式就是定义一个用于创建对象的接口&#xff0c;让…

echarts 地图点位图标为动图,且可以多个不同图标

根据项目需求,echarts地图点位图标要是动图,且可以设置不同图标,经过多方查找,找到解决方案,可以用svg使gif动起来 let myChartChina echarts.init(document.getElementById("myChartChina"), "transparent", {renderer: "svg"});其中transpare…

[当人工智能遇上安全] 10.威胁情报实体识别 (1)基于BiLSTM-CRF的实体识别万字详解

您或许知道&#xff0c;作者后续分享网络安全的文章会越来越少。但如果您想学习人工智能和安全结合的应用&#xff0c;您就有福利了&#xff0c;作者将重新打造一个《当人工智能遇上安全》系列博客&#xff0c;详细介绍人工智能与安全相关的论文、实践&#xff0c;并分享各种案…

vue请求代理查看真实地址

查看真实地址方式&#xff1a; 通过配置vue.config.js文件&#xff0c;直接在请求头输出完整地址&#xff1a; /api/: { changeOrigin: true, target: process.env.VUE_APP_PLATFORM_URL, logLevel: debug, // 在终端输出 onProxyRes(proxyR…

【Proteus仿真】【51单片机】拔河游戏设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用按键、LED、动态数码管模块等。 主要功能&#xff1a; 系统运行后&#xff0c;指示灯处于中间位置&#xff0c;数码管显示得分0&#xff0c;当按下…

C#中.NET Framework4.8 Windows窗体应用通过EF访问数据库并对数据库追加、删除记录

目录 一、应用程序设计 二、应用程序源码 三、生成效果 前文作者发布了在.NET Framework4.8 控制台应用中通过EF访问已有数据库&#xff0c;事实上在.NET Framework4.8 Windows窗体应用中通过EF访问已有数据库也是一样的。操作方法基本一样&#xff0c;数据库EF模型和上下文…

简易电路特性测试仪的设计(论文+源码)

1. 系统设计 系统主要由 STM32 单片机、DDS 模块、调理模块、特定放大器模块和电源模块 等组成。 DDS 模块使用低价格的 AD9833 芯片设计&#xff0c;产生调理模块需要的正弦信号。调理模块主要包 括特定放大器电路前端调理和后端调理&#xff1a;因为特定放大器进行性能…

2.3.5 交换机的VRRP技术

实验2.3.5 交换机的VRRP技术 一、任务描述二、任务分析三、具体要求四、实验拓扑五、任务实施1.交换机的基本配置 六、任务验收七、任务小结 一、任务描述 某公司的网络核心层原来采用一台三层交换机&#xff0c;随着网络应用的日益增多&#xff0c;对网络的可靠性也提出了越来…

使用vue2实现todolist待办事项

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

图论15-有向图-环检测+度数+欧拉回路

文章目录 1. 有向图设计1.1 私有变量标记是否有向1.2 添加边的处理&#xff0c;双向变单向1.3 删除边的处理&#xff0c;双向变单向1.4 有向图的出度和入度 2 有向图的环检测2.1 普通的算法实现换检测2.2 拓扑排序中的环检测 3 欧拉回路 1. 有向图设计 1.1 私有变量标记是否有…

Linux文件系统之inode

文章目录 1. 磁盘1.1 认识磁盘1.2 磁盘物理构造1.3 磁盘逻辑结构 2. 文件系统3. 如何理解目录 1. 磁盘 1.1 认识磁盘 文件 内容 属性&#xff0c;而文件是存储在磁盘上&#xff0c;那么可以理解为磁盘上存储的文件 存储的文件内容 存储的文件属性。 文件的内容采用的是块式…

深度学习 机器视觉 车位识别车道线检测 - python opencv 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

建造者模式(创建型)

目录 一、前言 二、建造者模式 三、链式编程实现建造者模式 四、总结 一、前言 当我们开发一个软件应用时&#xff0c;我们通常需要创建各种对象。有些对象是简单的&#xff0c;可以直接实例化&#xff0c;但有些对象则比较复杂&#xff0c;需要多个步骤才能创建完成。这时…