Linux线程_线程控制_线程库

一.线程控制

在Linux操作系统的视角,Linux下没有真正意义上的线程,而是用进程模拟的线程(LWP)。所以,Linux不会提供直接创建线程的系统调用,而是提供创建轻量级进程的接口。但是由于用户只认线程,所以pthread库会对下将Linux接口封装,对上给用户提供线程控制的接口,这种库被称为用户级线程库。 pthread 库在任何系统都要自带,因此也称原生线程库。

1.pthread_create() 创建线程

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

参数说明:

  1. pthread_t *thread(线程标识符LWP)

  2. const pthread_attr_t *attr

    • 这个参数用于指定线程的属性。如果为 NULL,则创建一个默认属性的线程。
  3. void *(*start_routine)(void *)(新线程要执行的函数)

  4. void *arg(该函数的参数)

返回值:

  • 如果成功,返回 0
  • 如果失败,返回一个错误码

我们知道pthread库会对Linux提供创建轻量级进程的接口进行封装,pthread_create()底层就是clone()系统调用。

int (*fn)(void*) 要执行的函数 

void* stack 线程独立的栈空间的指针

int flags 一个标志位参数,不同的标志控制不同的资源共享

void *arg 执行函数的参数

1.创建的新线程和main主线程谁先运行不确定。

2.给进程的时间片是固定的,进程里面的线程会对时间片进行瓜分。

3.如果多个线程执行的函数是同一个函数,该函数被重入。如果是不可重入函数就要添加保护。

4.进程定义的函数,每个线程都可以用。

5.全局变量在线程间是共享的

6.一个线程一旦异常,其它线程也会崩溃(如果给该进程内的所有线程发信号让它们退出,如何区分它们是否在一个进程里?它们会被链表维护起来,形成一个线程组)

7.线程栈不共享堆可以共享

栈不共享:不同线程栈中可能会有相同的变量名,线程自己在栈上定义的变量,等线程结束就会销毁。(并不是绝对访问不到,通过全局指针指向a线程栈上定义的变量,b线程也可以访问到,但不建议,有可能生命周期结束 访问到野指针)

堆共享:堆内存的分配在进程的地址空间内是全局可见的,不同线程通过同一个全局变量指针访问堆上数据。a线程申请了堆上空间,等a线程退出,堆空间也不会消失,需要delete手动释放。

8.传过去的参数arg,为什么是void类型?

便于传任何类型的参数。可以是变量 数字 结构体,如果要传多个参数就可以传一个结构体,里面包含要用到的参数。ThreadData *td=static_cast<ThreadData *>(args);对void*结构体进行转换.

2.pthread_join() 等待线程

pthread_join用于主线程等待其他线程的结束,并获取该线程的返回值。获取线程的执行结果

阻塞等待当前线程,直到指定的线程终止。

#include <pthread.h>int pthread_join(pthread_t thread, void **retval);

参数说明:

  • thread:要等待的线程的线程ID。该线程必须是已经创建并且未结束的线程。
  • retval:一个指向指针的指针,用于接收线程的返回值。如果不关心线程的返回值,可以将该参数设为 NULL

返回值:

  • 成功:返回 0
  • 失败:返回一个错误码,通常是一个负数。常见的错误包括:
    • ESRCH:指定的线程不存在或无效。
    • EINVAL:线程已经被取消或线程是主线程。

1.返回值void **retval,用法:
先定义个void *ret=nullptr,pthread_join(th,&ret); 此时ret=返回结果。

eg.返回常数return (void*)10 ,ret 类型虽然是void*指针,但里面不是地址而是常数10。想输出返回值cout<<(long long int)ret<<endl; (因为64位下指针大小8字节 用long long 8字节防止精度损失)

如果返回结构体,也可以Date *ret=nullptr; pthread_join(th,(void**)&ret); ret=返回结果,且ret类型为Date*

2.如果有一个类,里面有需要执行的函数,我想让不同线程执行不同函数,执行完成后再把结果存入类的成员变量中。最后让主线程把存入结果的所有成员变量输出。

定义一个全局的类对象,这样每个线程都可以访问到这个类对象,执行完成就把结果写入成员变量。但什么时候全部执行完呢?

pthread_join(th,nullptr)可以保证执行完成,执行结果写入成员变量。执行结果写入成员变量,可以不用接收返回值。也可以把类对象定义在主线程中,把类对象作为函数的参数,新线程中通过访问类对象执行相应函数。等到等待结束,就可以确定主线程中定义的类对象中所有成员变量都被写入结果。

3.pthread_exit() 线程退出

用于终止当前线程的函数。但对其它线程没有影响

void* retval 当前线程退出时的返回值 用pthread_join()接收

void pthread_exit(void *retval);

线程退出的方式:
1.自然退出 return 

2.显示退出 pthread_exit() 终止当前线程

3.异常退出 exit() 会让整进程退出,所有线程都被终止

4.pthread_cancel() 取消线程

用于请求取消另一个线程的函数。并不立即强制终止目标线程,而是发送一个取消请求,线程如何响应这个请求取决于该线程的状态和设置。

取消状态默认允许被取消,在某些合适的时机会终止。

int pthread_cancel(pthread_t thread);

thread 目标线程id

成功时返回 0。

失败时返回错误码。

取消线程必须要pthread_join(),获取的返回值为-1(PTHREAD_CANCELED)

线程会在某些“取消点”检查是否有取消请求,并作出响应。在实际应用中,使用pthread_cancel() 时需要谨慎,因为它可能会导致资源泄漏、数据不一致等问题

5.pthread_detach() 分离线程

用于将线程分离的函数。分离线程后,该线程的资源(包括线程的退出状态)会在线程结束时被自动回收不需要其他线程通过 pthread_join() 来等待它的结束或获取退出状态。

int pthread_detach(pthread_t thread);

主线程要执行自己的代码不想等待新线程,且不关心新线程返回值,可以创建新线程和分离它,可以自动回收资源,避免僵尸状态。

对分离的线程调用 pthread_join(),会返回 EINVAL 错误。

6.pthread_self() 获取线程id

获取调用它的当前线程的线程 ID

#include <pthread.h>pthread_t pthread_self(void);

二.理解线程库

1.线程id是什么?

我们有主线程和一个新线程,让它们打印自己的线程id用0x16进制打印。

这一长串数字像什么?这其实是地址。是虚拟地址

每个线程都可以调用pthread库的方法,是因为库映射到了进程的虚拟内存。

那我们想要获取线程的属性从哪里获取呢?对处理线程的方法由库封装提供,获取线程的属性,库也要对线程的属性进行提供,并维护

因此在库中保存着所有进程中每个线程的属性,而线程的id就是线程属性在地址空间的虚拟地址。

2.线程id和地址空间

我们现在知道所有线程的属性都存在库中,那保存线程属性的结构体是什么样的,具体分布又是如何呢?

mmap区域就是共享区,线程id指向pthread库中对应属性的地址。保存线程属性的结构体有三个字段

1.struct pthread 里面就是线程的属性 tid 状态 优先级...

2.线程栈 我们知道每个线程的栈空间都是独立的,用来保存局部变量 函数调用完成后的返回地址 切换上下文保存现场,只有主线程的栈是在地址空间的栈区 而新线程的栈是在共享区动态申请的(map出来的区域),每新建一个线程就在动态库中保存记录它的属性并申请栈空间,栈空间的大小可以设定。

3.线程的局部存储,__thread。我们知道定义的全局变量 int val=100,所有进程都可以看到,A线程修改了全局变量,B线程访问该全局变量时是修改后的全局变量。访问到的全局变量地址是同一个值。

但用__thread int val=100;对它进行修饰,A线程修改了全局变量,B线程访问该全局变量值仍不变,A B线程访问到的地址各不相同。

__thread 修饰全局变量,让原本独一份的全局变量,给每个线程各一份。相当于在每个线程中定义了一个局部变量。

有什么用呢?当我们要访问线程id时,每次都要去库里面找,效率低。__thread pthread_t tid; 将线程id缓存到里面,下次访问的时候提高效率。

__thread 只能修饰内置类型​​​​​​​

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络:运输层 —— TCP 的超时重传机制

文章目录 TCP 的超时重传超时重传时间的选择重传策略与拥塞控制的关联 TCP 的超时重传 TCP 的超时重传是保证数据可靠传输的重要机制之一 保证数据可靠性&#xff1a;通过超时重传机制&#xff0c;即使在网络状况不佳&#xff0c;出现数据包丢失等情况时&#xff0c;也能够确保…

C嘎嘎探索篇:和stack,queue的相遇

C嘎嘎探索篇&#xff1a;和stack&#xff0c;queue的再次相遇 前言&#xff1a; 小编在前几日刚完成了关于list容器的介绍&#xff0c;中间由于我牙齿出现了问题所以断更了不少天&#xff0c;如今我牙齿已经恢复&#xff0c;我也要开始继续新内容的讲解了&#xff0c;各位读者…

GPTZero:高效识别AI生成文本,保障学术诚信与内容原创性

产品描述 GPTZero 是一款先进的AI文本检测工具&#xff0c;专为识别由大型语言模型&#xff08;如ChatGPT、GPT-4、Bard等&#xff09;生成的文本而设计。它通过分析文本的复杂性和一致性&#xff0c;判断文本是否可能由人类编写。GPTZero 已经得到了超过100家媒体机构的报道&…

MyBatis Plus 项目的创建和使用

1. 快速上手 1.1. 项目的创建和配置 首先&#xff0c;创建一个 Spring Boot 工程&#xff0c;添加 MyBatis Plus 和 MySQL 对应的依赖&#xff0c;然后&#xff0c;和 MyBatis 一样&#xff0c;需要在 yml 文件中配置数据库连接信息 <dependency><groupId>com.b…

IDEA 2024.3 版本更新主要功能介绍

IDEA 2024.3 版本提供的新特性 IntelliJ IDEA 2024.3 的主要新特性&#xff1a; AI Assistant 增强 改进的代码补全和建议更智能的代码分析和重构建议Java 支持改进 支持 Java 21 的所有新特性改进的模式匹配和记录模式支持更好的虚拟线程调试体验开发工具改进 更新的 UI/UX 设…

Java编程,配置mongoUri连接mongodb时,需对特殊字符进行转义

一、背景 java程序连接mongo有两种方式&#xff1a; 用户名和密码方式uri方式 1、用户名和密码 以用户数据库为例&#xff0c;注意看它的密码 spring:data:mongodb:host: 192.168.10.17database: db_user_serviceport: 3717username: user_servicepassword: user_service3…

学习笔记|MaxKB对接本地大模型时,选择Ollma还是vLLM?

在使用MaxKB开源知识库问答系统的过程中&#xff0c;除了对接在线大模型&#xff0c;一些用户出于资源配置、长期使用成本、安全性等多方面考虑&#xff0c;还在积极尝试通过Ollama、vLLM等模型推理框架对接本地离线大模型。而在用户实践的过程中&#xff0c;经常会对候选的模型…

Python 快速入门(上篇)❖ Python基础知识

Python 基础知识 Python安装**运行第一个程序:基本数据类型算术运算符变量赋值操作符转义符获取用户输入综合案例:简单计算器实现Python安装** Linux安装: yum install python36 -y或者编译安装指定版本:https://www.python.org/downloads/source/ wget https://www.pyt…

【1.2 Getting Started--->Installation Guide】

NVIDIA TensorRT DOCS 此 NVIDIA TensorRT 10.6.0 安装指南提供安装要求、TensorRT 包中包含的内容列表以及安装 TensorRT 的分步说明。 安装指南 摘要&#xff1a; 本 NVIDIA TensorRT 10.3.0 安装指南提供了安装要求、TensorRT 软件包中包含的内容列表以及安装 TensorRT 的…

RT_Thread内核源码分析(三)——线程

目录 1. 线程结构 2. 线程创建 2.1 静态线程创建 2.2 动态线程创建 2.3 源码分析 2.4 线程内存结构 3. 线程状态 3.1 线程状态分类 3.2 就绪状态和运行态 3.3 阻塞/挂起状态 3.3.1 阻塞工况 3.4 关闭状态 3.4.1 线程关闭接口 3.4.2 静态线程关闭 3.4.3 动态线程关…

Unity图形学之CubeMap立方体贴图

1.CubeMap&#xff1a;有六个面的贴图组成 2. 假反射&#xff1a;反射天空盒子 &#xff08;1&#xff09;正常UV采样&#xff1a; &#xff08;2&#xff09;Cube的采样&#xff1a;利用反射角采样&#xff0c;反射角X和Cube的交点采样 Shader "Custom/TestReflect"…

C语言基础学习:抽象数据类型(ADT)

基础概念 抽象数据类型&#xff08;ADT&#xff09;是一种数据类型&#xff0c;它定义了一组数据以及可以在这组数据上执行的操作&#xff0c;但隐藏了数据的具体存储方式和实现细节。在C语言中&#xff0c;抽象数据类型&#xff08;ADT&#xff09;是一种非常重要的概念&…

Qt-多元素控件

Qt中的多元素控件 Qt提供的多元素控件有&#xff1a; 这里的多元素控件都是两两一对的。 xxWidget和xxView的一个比较简单的理解就是&#xff1a; xxView是更底层的实现&#xff0c; xxWidget是基于xxView封装来的。 可以说&#xff0c;xxView使用起来比较麻烦&#xff0c;但…

2023年9月GESPC++一级真题解析

一、单选题&#xff08;每题2分&#xff0c;共30分&#xff09; 题号 123456789101112131415 答案 CDBCDBACACBBDDA 1. 我们通常说的 “ 内存 ” 属于计算机中的&#xff08;&#xff09;。 A. 输出设备 B. 输 ⼊ 设备 C. 存储设备 D. 打印设备 【答案】 C 【考纲知识点】…

wend看源码-APISJON

项目地址 腾讯APIJSON官方网站 定义 APIJSON 可以定义为一个面向HTTP 协议的JSON 规范&#xff0c;一个面向数据访问层的ORM 框架。其主要工作流程包括&#xff1a;前端按照既定格式组装 JSON 请求报文&#xff0c;通过 APIJSON-ORM 将这些报文直接转换为 SQL 语句&#xff0c…

VMware虚拟机Ubuntu桥接模式突然连接不上网络解决办法

在Linux环境进行开发时突然发现虚拟机中的Ubuntu突然连接不上网络&#xff0c;图形化界面也找不到有线连接选项。在此记录解决办法。 解决办法 1. 在终端命令行输入以下命令&#xff1a; sudo service network-manager stop2. 然后编辑以下文件将其中NetworkingEnable fals…

丹摩征文活动|摩智算平台深度解析:Faster R-CNN模型的训练与测试实战

目录 文章前言Faster R-CNN的简介Faster RCNN的训练与测试提前准备1.1 mobaxterm&#xff08;远程连接服务器&#xff09;1.2 本文的源码下载 目标检测模型 Faster-Rcnn2.1云服务器平台 数据上传内置JupyterLab的使用本地连接使用DAMODEL实例获取实例的SSH访问信息通过SSH连接通…

【数据结构】归并排序 —— 递归及非递归解决归并排序

归并排序 一、归并排序1、归并排序的思想2、归并排序代码实现&#xff08;递归&#xff09;<1> 归并排序的递归区间<2> 归并排序的稳定性<3> 拷贝 3、归并排序代码实现&#xff08;非递归&#xff09;<1> 循环区间溢出问题 二、总结 一、归并排序 1、…

调大Vscode资源管理器字体

对于调整资源管理器字体大小&#xff08;也就是下图红框&#xff09;&#xff0c;查找了网上很多方法。要么介绍的方法是调整了代码字体&#xff0c;要么是调节了终端字体&#xff0c;要么是通过整体放缩实现的调整&#xff0c;总之都不合适。 唯一的调整方法是在几篇CSDN里看到…

【Linux】-学习笔记04

第十二章、磁盘管理 1.查看磁盘空间使用量 1.1df命令 作用&#xff1a; 列出文件系统的磁盘空间占用情况 df&#xff0c;disk free&#xff0c;通过文件系统来快速获取空间大小的信息&#xff0c;当我们删除一个文件的时候&#xff0c;这个文件 不是马上就在文件系统当中消…