Linux学习之路 -- 线程控制

news2024/11/13 18:07:36

前面我们介绍了线程的基础概念,即线程为进程内部的执行分支。下面我们将介绍一下具体的线程控制相关函数。

目录

1、铺垫

2、线程创建

3、线程等待

4、线程异常

5、线程退出

<1>线程函数返回退出

<2>pthread_exit

<3>pthread_cancel

6、线程优点

7、线程的缺点

8、Linux进程VS线程


1、铺垫

在正式介绍线程控制之前,我们需要一点铺垫知识。在我们上层的用户看来,其实系统中是存在线程和进程的区分。而实际上,Linux中并没有真正的线程,所以Linux系统并没有提供相应的系统调用。为了让相应接口符合用户的认知,我们就必须在内核上层封装一层线程库,把相应的系统调用变成线程。这个线程库我们称为原生线程库,每个Linux操作系统在安装时,都必须自带。在我们编写多线程的代码时,都必须手动去连接该库,否则会出现异常。

2、线程创建

第一个参数为输出型参数,我们可以理解成线程id,我们需要定义一个pthread_t 的变量,然后将该变量的地址传入进去。第二个参数用于设置线程的属性,不过这里我们一般设置为nullptr即可。第三个参数是一个函数指针,在新线程被创建之后,会去执行函数所指向的代码。第四个参数为第三个参数中的变量。

我们以一个小样例来演示一下该接口的用法

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
using namespace std;

void* handler(void *arg)
{
    while (1)
    {
        sleep(1);
        std::cout << "I am pthread-1 " << "pid is : " << getpid() << endl;
    }
}
int main()
{
    pthread_t thread;
    pthread_create(&thread, nullptr, handler, nullptr);
    while(1)
    {
        sleep(1);
        std::cout << "I am pthread -2 " <<  "pid is : " << getpid() << endl;
    }
    return 0;
}

运行之后的结果

 我们可以看见,两个线程的pid是一样的,这也侧面说明了线程是进程内部的一个执行分支。如果我们想在shell会话中看到两个线程相关的信息,我们可以使用ps -aL命令。这两线程调用的先后由调度器决定,不必纠结其顺序。

其中LWP代表轻量级进程的意思,这个参数我们可以认为它是线程的id(内核中),我们cpu在调度时,也是使用这个参数。需要注意的是,如果进程中只有一个线程,线程的id会和进程id一致。上图中的主线程id也和进程的pid数值是一样的。

上面所述的id用于内核标识线程,而用户标识线程的id,一般是在pthread_create接口的第一个参数上获取。当然,我们也可以使用pthread_self也可以获取用户级别的id。至于这个id的具体是什么东西,这里暂不介绍。

这里我们可以验证一下线程和进程之间的一些异同点,就比如主线程(main函数中的线程)退出,其他的线程是否会退出呢?我们稍微修改一下代码,将主线程休眠2秒后结束。

我们可以发现,在主线程退出后,其他的线程也就跟着退出了。所以我们可以得出一个结论:主线程退出 = 主进程退出 = 所有的线程都退出。而这就要求我们的主线程一般就是最后退出,而且线程也需要被wait,否则也造成类似于内存泄露的问题。

3、线程等待

第一个参数就是我们自己创建pthread_t变量,这里需要传入该变量在线程创建函数后的值。第二个参数我们不做详细的介绍,这是一个指针的地址,该指针用于存储线程函数的返回值(也就是上新建线程所执行函数的返回值),这里我们设置为nullptr即可。

等待成功返回0,失败返回错误码。

4、线程异常

在正常情况下,线程退出一般就有三种情况:一是代码跑完,结果是正确的;二是代码跑完,结果不正确;三是代码出现异常。前面的两种情况,我们可以通过新线程执行函数的返回值来进行判断,后面一种情况出现,进程会直接退出,所有的线程都会挂掉。这是因为当线程出现异常时,系统会检测到异常并向进程发送信号,进程收到信号,就会被终止。无论哪个线程出异常,代表就是整个进程出现异常。这也是为什么pthread_join没有对线程异常做处理的原因,这是因为出现异常,根本就轮不到pthread_join来回收。而这个异常就需要其父进程来考虑了。

同一进程内的数据大部分是被线程共享的(这里可以通过访问同一个全局变量证明,让单个线程对变量修改,观察另外的线程中该全局变量是否改变),虽然这方便了各个线程之间进行数据传输,但是这也削弱了线程的健壮性。

5、线程退出

线程退出有多种方式,这里简单介绍一下。

<1>线程函数返回退出

当线程函数执行完毕时,通过返回函数,线程会自行退出。

<2>pthread_exit

注意区分和exit的区别,exit是用来让进程退出的,而pthread_exit才是用来让线程退出的。

参数是void* 类型,我们可以这样使用(void*)+数字;

<3>pthread_cancel

这种退出方式,我们需要确保新线程已经被创建运行。

传入需要取消线程的id变量。成功返回0,失败返回错误码(这种方式不推荐)

6、线程优点

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

优点主要集中在前两点,第一个优点已经提到过,下面着重介绍一下第二个优点。
        这个优点不单单体现在让寄存器少了几次交互(这个不是重点),而是我们cpu中存在一块存储空间较大的缓存(cache),cpu要执行每条命令都需要在内存中进行读取,为了提高效率,cpu会直接读取一条代码后面的一大段代码,大概率后面要执行的内容就在这段代码当中。如果没有命中,也没有关系,后续直接跳转到需要执行的地方(概率比较低)。这块缓存的大小一般比较大,常是kb或mb。如果进程进行切换,这块缓存上的数据就需要重新加载。而同一进程线程在切换时,由于是共享绝大部分的资源,所以在cache中的数据大概率可以不用重新加载,这个重新加载的过程一般是很慢的。这才是影响其效率的主要原因。

7、线程的缺点

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

8、Linux进程VS线程

1、进程是资源分配的基本单位线程是调度的基本单位
2、线程共享进程数据,但也拥有自己的一部分数据:
        <1>线程ID
        <2>一组寄存器(cpu中的硬件上下文)
        <3>栈(地址空间中的独立线程栈)
        <4>errno
        <5>信号屏蔽字
        <6>调度优先级
进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
        <1>文件描述符表
        <2>每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
        <3>当前工作目录
        <4>用户id和组id

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

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

相关文章

QT安装Qt Creater创建项目时无法选择Kit选项 No suitable kits found

1、安装QT时会遇到安装完qt&#xff0c;打开Qt Creater&#xff0c;新建工程时遇到无法选择Kit选项 No suitable kits found而无法下一步的问题。原因及解决方法如下&#xff1a; 2、原因&#xff1a; 因为在安装qt时&#xff0c;选择了错误的minGW&#xff0c;如下图&#xf…

【笔记】Java EE应用开发环境配置(JDK+Maven+Tomcat+MySQL+IDEA)

一、安装JDK17 1.下载JDK17 https://download.oracle.com/java/17/archive/jdk-17.0.7_windows-x64_bin.zip 2.配置环境变量 下载后&#xff0c;解压到本地&#xff08;目录中最好不要有中文或特殊字符&#xff09; 打开【控制面板】-【系统和安全】-【系统】-【高级系统…

Liunx:理解进程概念

一、进程概念 进程有两种可以理解的方式&#xff1a; 1、已经加载到内存中的程序&#xff0c;叫做进程。 2、正在运行的程序&#xff0c;叫做进程 从概念上挺好理解的&#xff0c;我们运行一个程序必然要通过CPU&#xff0c;所以自然需要加载到内存中…… 但我们应该关注的是&a…

Java反射:如何判断对象属性是否为static或final

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 在Java编程中&#xff0c;反射是一种强大的工具&#xff0c;允许在运行时检查类、接口、字段和方法的信息。通过反射&#xff0c;可以动态地创建对象、调用方法和访问字段&#xff0c;甚至可以修改私有字段的值。然而…

大模型:中国AI Agent应用研究报告2024

自2023年3月&#xff0c;以AutoGPT为代表的一系列技术框架的发布&#xff0c;Al Agent以其自主性和解决问题的能力&#xff0c;迅速获得科技圈各方讨论。并在之后一年多的时间中&#xff0c;陆续发布多项不同种类的技术框架。除了使用领域的探索之外&#xff0c;单智能体和多智…

2024华为OD统一考试题库清单(持续收录中)以及考点说明(Python/JS/C/C++篇)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

大模型新书分享《大模型入门:技术原理与实战应用》(附PDF)

这本大模型书籍已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 新书速递 书名&#xff1a; 大模型入门&#xff1a;技术原理与实战应用 ISBN&#xff1a; 9787115638816 作者&#xff1a; 程絮森&#xff0c;杨波&am…

产品经理的发现和成长

获取更多资料&#xff0c;见下图

原装N9000B信号分析仪keysight/N9000B,N9000A详情参数

是德Keysight N9000B CXA 信号分析仪&#xff0c;多点触控&#xff0c; 特征&#xff1a; 9 kHz 至 26.5 GHz 的宽频率范围以及高达 25 MHz 的分析带宽让您了解更多 为手动和自动化制造测试系统添加可靠的信号分析 执行基本测量&#xff0c;例如杂散搜索和失真分析 使用可选…

1658.将x减到0的最小操作数

题目 链接&#xff1a;leetcode链接 思路分析&#xff08;滑动窗口&#xff09; 题目要求从最左边或者最右边移除元素&#xff0c;需要思考两侧&#xff0c;这是比较麻烦的。 正难则反&#xff0c;我们逆向思维一下&#xff0c;最后剩余的元素是不是中间的连续区间&#xf…

人工智能 | Hugging Face 的应用

大纲 Hugging-Face 介绍 Hugging-Face 大语言模型 LLM 管理Transformers 机器学习框架文本生成推理 (TGI) Hugging Face Hugging-Face – 大语言模型界的 Github Hugging Face 专门开发用于构建机器学习应用的工具。该公司的代表产品是其为自然语言处理应用构建的 transfo…

网络编程(学习)2024.9.5

目录 网络协议头分析 MTU MSS 粘包和拆包 粘包 粘包原因 解决粘包 拆包 包头分析 以太网头 IP头 ​编辑 Tcp头 三次握手和四次挥手 三次握手 四次挥手 TCP可靠性的保证 1. 数据包顺序 2. 数据完整性 3.. 确认应答&#xff08;ACK&#xff09; 4. 重传机制…

springboot个性化大学生线上聊天交友系统

基于springbootvue实现的个性化大学生线上聊天交友系统 &#xff08;源码L文ppt&#xff09;4-017 4系统设计 4.1 软件功能模块设计 个性化大学生线上聊天交友分为两个模块&#xff0c;分别是管理员功能模块和用户功能模块。主要功能模块包括&#xff…

探索数据可视化的奥秘:Seaborn库的魔力

文章目录 探索数据可视化的奥秘&#xff1a;Seaborn库的魔力背景&#xff1a;为何选择Seaborn&#xff1f;Seaborn是什么&#xff1f;如何安装Seaborn&#xff1f;简单函数介绍与示例场景应用示例常见问题与解决方案总结 探索数据可视化的奥秘&#xff1a;Seaborn库的魔力 背景…

ApiOps Helper:本地代码智能扫描,API的注册管理自动化

APIOps Helper是什么 APIOps Helper是在IntelliJ IDEA平台上开发的插件&#xff0c;可以自动识别IDEA中Java项目的代码&#xff0c;从中扫描出API并自动生成OpenAPI规范文档。 用户可以选择将API导出为本地OpenAPI规范文档&#xff0c;或者将API同步到APIOps平台上进行API协同…

挑选展厅设计伙伴?这些考量点助你决策

如今&#xff0c;随着数字化技术的快速发展&#xff0c;内容展览展示行业已经脱变为一个汇聚创新与创意的展示空间&#xff0c;并成为企业、文旅等各行业竞相追捧的平台&#xff0c;因此&#xff0c;挑选一家专业的多媒体展厅设计公司显得尤为重要&#xff0c;但是&#xff0c;…

maestro复制

problem&#xff1a;ADE Explore的maestro 里保存了设置的仿真器Analyses和扫描参数 Design Variables&#xff0c;如果要新建一个当前的testbench副本&#xff0c;除了复制schematic还希望能把maestro一起复制过去。但是直接复制maestro后仿真的时候还是对原有的schemetic在仿…

能否使用PLC无线通信模块实现力控与FX5U无线以太网通信?

在实际系统中&#xff0c;车间里分布多台PLC&#xff0c;需要用上位机软件集中控制。通常所有设备距离在几十米到上百米不等。用户会选择以太网方式是因为传输速度有保障&#xff0c;而选择无线以太网方案是因为不想开挖电缆沟&#xff0c;或者布线不方便&#xff0c;不但施工麻…

AR远程协作与Web,视频会议,监控直播融合方案

​​随着全球化的加速和远程工作的普及&#xff0c;团队成员之间的沟通与协作变得更加重要。传统的远程协作方式存在诸多限制&#xff0c;如沟通不畅、信息共享困难等。AR技术以其独特的交互性和沉浸感&#xff0c;为远程协作提供了新的解决方案。 针对视频会议系统在特殊场景…

SprinBoot+Vue兼职发布平台的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…