线程,你是个什么?

news2024/11/25 18:51:38

线程的基本定义

线程(Thread)是操作系统能够进行运算调度的最小单位,它被包含在进程(Process)中,是进程中的实际运作单位。一个线程可以与同一进程中的其他线程共享进程的全部资源,包括内存、文件和网络连接等。由于线程之间共享内存,所以线程之间的通信更加高效,在多处理器系统中,多个线程可以并发执行,从而提高了系统的并发性能。

为什么要引入线程

引入线程的主要目的是提高程序的并发性能和效率。在单线程程序中,如果某一个任务阻塞了整个程序,那么整个程序都会停止执行,而多线程程序可以实现并发执行,即使其中的某一个线程被阻塞了,其他线程仍然可以继续执行。

另外,多线程程序也可以更好地利用计算机资源,因为多个线程可以在不同的 CPU 上运行。此外,线程之间可以共享数据,这样在处理一些需要共享数据的任务时,线程间的通信更加高效。

总的来说,引入线程可以提高程序的并发性能和效率,提高系统的资源利用率,并且简化代码编写过程,使得程序更加易于开发和维护。

用户级线程是由用户程序管理的线程,而不是由操作系统内核管理的线程。在使用用户级线程时,应用程序会自己维护线程调度、同步和通信等,并且运行在用户空间中。

相比之下,操作系统内核管理的线程 (也称为内核级线程) 能够充分利用多核处理器。这是因为每个内核都可以独立地执行一个线程,从而使多个线程可以并行执行,提高了系统的并发性能。

然而,用户级线程不能直接利用多核处理器。这是因为用户级线程的调度是由应用程序自己管理的,而应用程序无法控制在哪个核心上运行线程或者将线程分配到哪个核心上。因此,即使有多个核心可用,用户级线程仍然只能在单个核心上运行,无法实现真正的并行执行。

虽然用户级线程不能直接利用多核处理器,但是可以通过一些技术来实现多核并行。例如,可以使用线程池或者任务调度器来管理线程,并将任务分配给不同的线程执行。这些技术可以在用户级别上实现多核并行,但是需要应用程序自己实现线程调度、同步和通信等,复杂度较高。

线程的创建

pthread_create() 是 POSIX 线程库中的一个函数,用于创建新线程。

该函数的原型如下:


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

它需要传入以下四个参数:

  • thread:指向 pthread_t 类型的指针,用于存储新线程的 ID。
  • attr:指向 pthread_attr_t 类型的指针,用于设置线程属性。如果不需要特别设置线程属性,则可以将该参数设置为 NULL。
  • start_routine:指向函数的指针,新线程将从该函数开始执行。该函数必须返回 void * 类型,并且接受一个 void * 类型的参数。
  • arg:传递给 start_routine 函数的参数。

当成功创建新线程时,pthread_create() 函数会返回 0,否则返回错误码。在新线程执行完毕之前,创建该线程的线程应该一直等待该线程的结束,以保证不会出现资源泄漏或者竞争问题。可以使用 pthread_join() 函数来等待一个线程完成执行并回收它的资源。

用户级线程和内核级线程

用户级线程和内核级线程是两种不同的线程实现方式。

用户级线程是由应用程序自己创建和管理的线程,操作系统并不感知它们的存在。用户级线程的调度、同步和通信都由应用程序自己负责,因此具有更高的灵活性和效率。但是,由于操作系统无法感知用户级线程的存在,因此在遇到阻塞等问题时,整个进程都会被挂起,导致资源利用率下降。

内核级线程是由操作系统创建和管理的线程,它们直接映射到操作系统的内核线程上,并由操作系统负责调度、同步和通信。由于操作系统可以感知内核级线程的存在,因此在遇到阻塞等问题时,可以将一个线程挂起而不影响整个进程的执行。但由于内核级线程需要频繁地从用户态切换到内核态,因此会带来额外的开销和延迟。

在实际应用中,一般采用混合型线程模型,即在应用程序中使用用户级线程,在操作系统内核中使用内核级线程。这样可以兼顾灵活性和效率,同时也能够利用操作系统的优点来解决阻塞等问题。

进程的创建和终止

在这里插入图片描述

线程函数的错误处理

之前的POSIX系统调用和库函数在调用出错的时候,通常会把全局变量 errno 设置为一个特别的数值以
指示报错的类型,这样就可以调用 perror 以显示符合人阅读需求的报错信息。但是在多线程编程之
中,全局变量是各个线程的共享资源,很容易被并发地读写,所以pthread系列的函数不会通过修改
errno 来指示报错的类型,它会根据不同的错误类型返回不同的返回值,使用 strerror 函数可以根据
返回值显示报错字符串。

线程的主动退出

使用 pthread_exit 函数可以主动退出线程,无论这个函数是否是在 start_routine 中被调用,其行为类似于进程退出的 exit 。 pthread_exit 的参数是一个 void * 类型值,它描述了线程的退出状态。在start_routine 中使用return语句可以实现类似的主动退出效果,但是其被动退出的行为有一些问题,所以使用较少。线程的退出状态可以由另一个线程使用 pthread_join 捕获,但是和进程不一样的是,另一个线程的选择是任意的,不需要是线程创建者。

获取线程退出状态

调用 pthread_join 可以使本线程处于等待状态,直到指定的 thread 终止,就结束等待,并且捕获到的线程终止状态存入 retval 指针所指向的内存空间中。因为线程的终止状态是一个 void * 类型的数据,所以 pthread_join 的调用者往往需要先申请8个字节大小的内存空间,然后将其首地址传入,在pthread_join 的执行之后,这里面的数据会被修改。有些时候,内容可能是一片数据的首地址,还有些情况下内容就是简单的一个8字节的整型。

线程的取消

int pthread_cancel(pthread_t thread);

查看线程的状态

$ps -elLf

线程资源清理

在引入线程取消之后,程序员在管理资源回收的难度上会急剧提升。为了简化资源清理行为,线程库引入了 pthread_cleanup_push 和pthread_cleanup_pop 函数来管理线程主动或者被动终止时所申请资源(比如文件、堆空间、锁等等)。

void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);

pthread_cleanup_push 负责将清理函数压入一个栈中,这个栈会在下列情况下弹出:

  1. 线程因为取消而终止时,所有清理函数按照后进先出的顺序从栈中弹出并执行。
  2. 线程调用 pthread_exit 而主动终止时,所有清理函数按照后进先出的顺序从栈中弹出并执行。
  3. 线程调用 pthread_clean_pop 并且 execute 参数非0时,弹出栈顶的清理函数并执行。
  4. 线程调用 pthread_clean_pop 并且 execute 参数为0时,弹出栈顶的清理函数不执行。

线程的同步和互斥

在多线程编程中,用来控制共享资源的最简单有效也是最广泛使用的机制就是 mutex(MUTualEXclusion) ,即互斥锁。锁的数据类型是pthread_mutex_t ,其本质是一个全局的标志位,线程可以对作原子地测试并修改,即所谓的加锁。当一个线程持有锁的时候,其余线程再尝试加锁时(包括自己再次加锁),会使自己陷入阻塞状态,直到锁被持有线程解锁才能恢复运行。所以锁在某个时刻永远不能被两个线程同时持有。
创建锁有两种形式:直接用 PHTREAD_MUTEX_INITIALIZER 初始化一个 pthread_mutex_t 类型的变量,即静态初始化锁;而使用pthread_mutex_init 函数可以动态创建一个锁。动态创建锁的方式更加常见。

使用 pthread_mutex_destory 可以销毁一个锁。

pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t
*mutexattr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);

什么是取消点
在 Linux 中,线程的取消点(Cancellation Point)是指在执行某些操作期间可以被取消的特定点。当一个线程被请求取消时,它会在下一个取消点上停止执行,这使得线程可以更容易地被终止或暂停。

Linux 系统中的许多函数都是取消点,包括 I/O 操作、等待系统调用、锁操作等。当线程执行到这些函数时,它们将检查是否有取消请求,并在必要时允许线程被取消。例如,在使用 pthread 库创建的线程中,pthread_join() 是一个取消点。

如果线程没有在取消点上阻塞,则取消请求将被延迟,直到线程到达下一个取消点,这可能会导致一些延迟。因此,在编写多线程应用程序时,需要考虑取消点的影响,以确保及时响应取消请求。

当调用 pthread_cancel() 函数请求取消一个线程时,操作系统并不会立即终止该线程,而是将一个“取消请求”标记设置为该线程。然后,当线程到达一个取消点时,它会检查是否有取消请求,并在必要时执行线程取消操作。

以下是 pthread_cancel() 函数的大致流程:

pthread_cancel() 函数被调用,将一个“取消请求”标记设置为目标线程。
目标线程在到达取消点时,会检查是否有取消请求,如果有,则开始执行线程取消操作。
线程取消操作分为两个步骤:设置取消状态和执行取消动作。
设置取消状态:线程首先将自己的“取消状态”设置为 DISABLE,以避免在取消过程中被再次取消。此外,如果线程被取消时正在持有锁,则需要释放这些锁,以避免死锁问题。
执行取消动作:线程执行一些特定的操作来实现线程取消,例如释放资源、清理堆栈、发送信号等。
如果线程没有到达取消点,取消请求将被延迟,直到线程到达下一个取消点。在这种情况下,线程将继续运行,除非取消请求被处理或取消点被触发。
当线程完成取消操作后,它将从线程函数中返回,或者通过调用 pthread_exit() 函数来退出线程。
需要注意的是,线程取消操作可能会导致一些副作用,例如未完成的 I/O 操作、资源泄露、死锁等。因此,在使用 pthread_cancel() 函数时,需要谨慎处理取消操作,并确保及时释放资源。

线程安全

线程安全是指在多个线程并发执行的情况下,程序仍然能够正确地工作,而不会出现数据竞争、死锁、活锁等问题。具有线程安全性的程序能够保证每个线程都可以正确、独立地访问共享资源,并且在多个线程同时访问同一共享资源时,结果与串行执行的结果一致。

在一个线程不安全的程序中,如果多个线程同时访问共享资源,则可能会导致数据损坏、内存泄漏、死锁或其他意外行为。例如,在多个线程之间读写共享变量时,如果没有采用适当的同步机制,就可能会出现竞态条件(race condition)和数据竞争(data race),导致程序产生错误的结果。

因此,编写具有线程安全性的程序是非常重要的,特别是在需要处理多任务和并发访问的场景下。常见的提高程序线程安全性的方法包括使用互斥锁、信号量、条件变量、原子操作等技术来实现对共享资源的同步和互斥访问。

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

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

相关文章

深入浅出讲解闭包及其原理

闭包 什么是闭包&#xff1f; 闭包的概念并不复杂&#xff0c;但是它的定义比较绕&#xff08;就像平时经常用到它&#xff0c;却又说不出来是什么&#xff09;。可以在一个作用域中调用函数的内部函数并访问到该函数中的作用域的成员&#xff0c;这就是闭包。给一个建议&…

springboot整合swagger3

目录 一、导入swagger3的依赖二、SwaggerConfig代码的解读三、整体代码四、访问swagger3 一、导入swagger3的依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</versi…

【算法与数据结构】209.长度最小的子数组

文章目录 题目一、暴力穷解法二、滑动窗口法完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 题目 一、暴力穷解法 思路分析&#xff1a;这道题涉及到数组求和&#xff0c;那么我们很容易想到利用两个for循环来写&#xff0c;…

【科技素养题】少儿编程 蓝桥杯青少组科技素养题真题及解析第20套

少儿编程 蓝桥杯青少组科技素养题真题及解析第20套 1、“唐纳德特朗普 (Donald Trump) 曾经是美国总统”是一个 (),“特朗普关于新冠肺炎疫情的不实言论”是一个 ()。 A、事实;事实 B、观点;事实 C、观点;观点 D、事实;观点 答案:D 考点分析:主要考查小朋友们对时事的…

ChatGPT的未来发展

文章目录 1.什么是ChatGPT2.ChatGPT的基础技术3.ChatGPT工作原理4.ChatGPT应用场景5.ChatGPT局限性6.ChatGPT的未来发展 ✍创作者&#xff1a;全栈弄潮儿 &#x1f3e1; 个人主页&#xff1a; 全栈弄潮儿的个人主页 &#x1f3d9;️ 个人社区&#xff0c;欢迎你的加入&#xff…

【严重】vm2 <3.9.18 沙箱逃逸漏洞(存在POC)

漏洞描述 vm2 是一个基于 Node.js 的沙箱环境&#xff0c;可以使用列入白名单的 Node 内置模块运行不受信任的代码&#xff0c;代理对象用于拦截并重定义宿主对象的各种操作。 vm2 3.9.18之前版本中&#xff0c;由于 prepareStackTrace 函数直接由 V8 引擎调用&#xff0c;其…

Linux命令(30)之ps

Linux命令之ps 1.ps介绍 linux命令ps是用来查看系统进程的命令。类似与Windows任务管理器中查看到的进程的功能。 2.ps用法 ps [参数] ps常用参数 参数说明-A显示所有的进程数据-a显示跟当前终端关联的所有进程-u基于用户的格式显示-x显示所有进程&#xff0c;不以终端机来…

chatgpt赋能python:用Python建立600*600画布,打造更好的数据可视化!

用Python建立600*600画布&#xff0c;打造更好的数据可视化&#xff01; 简介 数据可视化是数据分析的重要工具之一&#xff0c;通过可视化工具可以更加直观地展现数据&#xff0c;帮助人们更好地理解数据。而Python语言中的matplotlib库正是其中一款功能强大的数据可视化工具…

如何提升自身 WEB 渗透能力?

前言 web 渗透这个东西学起来如果没有头绪和路线的话&#xff0c;是非常烧脑的。 理清 web 渗透学习思路&#xff0c;把自己的学习方案和需要学习的点全部整理&#xff0c;你会发现突然渗透思路就有点眉目了。 程序员之间流行一个词&#xff0c;叫 35 岁危机&#xff0c;&am…

基于MATLAB的Filter使用,低通、带通和高通滤波器的MATLAB程序分享

基于MATLAB的Filter使用&#xff0c;低通、带通和高通滤波器的MATLAB程序分享 完整程序如下&#xff1a; clear all close all clc %% Parameter Interface Frequence0 60; %单位&#xff1a;Hz Frequence1 130; %单位&#xff1a;Hz F…

002-从零搭建微服务-认证中心(二)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff1a;https://gitee.com/csps/mingyue 文档地址&#xff1a;https://gitee.com/csps/mingyue/wikis 创建新项目 MingYue Idea 创建 maven 项目这…

【算法与数据结构】59、LeetCode螺旋矩阵2

文章目录 题目一、方向向量法完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 题目 一、方向向量法 思路分析&#xff1a;螺旋矩阵在旋转过程中&#xff0c;我们选择的区间是左闭右开区间[ , ]&#xff0c;例如方向为从左往右…

【玩转Linux操作】Ubuntu创建桌面快捷方式

&#x1f38a;专栏【玩转Linux操作】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 目录 &#x1f34e;进入applications文件夹 &#x1f34e;选择需要添加到…

chatgpt赋能python:Python开发平台软件的重要性

Python开发平台软件的重要性 随着科技的不断进步和软件开发的发展&#xff0c;Python语言逐渐成为最受欢迎和广泛使用的编程语言之一。作为一门高级编程语言&#xff0c;Python具有简单易懂的语法和强大的功能&#xff0c;能够帮助开发者快速构建复杂的应用程序和网站。Python…

初学者应该怎么学git-下

初学者应该怎么学git-下 Git 文件管理 文件四种状态 ● 版本控制就是对文件的版本控制&#xff0c;在Git 管理中&#xff0c;文件被统一管理&#xff0c;有四个状态 Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git 库, 不参与版本控制. 通过git add 状态变为Stage…

高性能网络应用框架

技术主题 Netty从本质上讲是一个高性能网络应用框架&#xff0c;之所以说是高性能&#xff0c;依赖于Netty的线程模型。 一网络编程性能的瓶颈 BIO 模型里&#xff0c; read() 操作和 write() 操作都会阻塞当前线程的&#xff0c;如果客户端已经和服务端建立了一个连接&…

【基于IMX6ULL驱动开发学习】01.安装交叉编译环境【附下载地址】

第一步&#xff08;下载工具链&#xff09;&#xff1a; 从官网上下载交叉编译工具链 https://snapshots.linaro.org/gnu-toolchain/ 按照以下步骤选择 可以选择最新的&#xff08;我也忘记我用的哪个版本了&#xff0c;都可以用问题不大&#xff09; 第二步&#xff08;…

chatgpt赋能python:Python库函数:提高开发效率的利器

Python库函数&#xff1a;提高开发效率的利器 Python作为一门高级编程语言&#xff0c;被广泛应用于 Web开发、科学计算、机器学习、数据分析等领域。它的可读性强、语法简单、库函数丰富是其广受欢迎的原因之一。本文将带您了解Python库函数的优势并介绍几个常用的库函数。 …

大型语言模(LLM) 之 提示词工程(三)

今天我学习了DeepLearning.AI的 Prompt Engineering 的在线课程&#xff0c;我想和大家一起分享一下该门课程的一些主要内容。以下是我写的关于该课程的前两篇博客&#xff1a; 大型语言模(LLM)之提示词工程(一) 大型语言模(LLM)之提示词工程(二) 今天我们来学习第三部分内容…

【express模块】课程笔记

目标&#xff1a; express.static()快速托管静态资源express路由精简项目结构常见express中间件使用express创建API接口在express中启用cors跨域资源共享 目录 一. 初识Express 1.1 Express简介 1. 什么是express 2. 进一步理解Express 3. Express能做什么 1.2 Express…