【Linux】Linux线程

news2024/11/27 22:26:58

一、Linux线程的概念

1.什么是线程

1.一个进程的一个执行线路叫做线程,线程的一个进程内部的控制序列。

2.一个进程至少有一个执行线程

3.线程在进程内部,本质是在进程地址空间内运行

4.操作系统将进程虚拟地址空间的资源分配给每个执行流,就成了线程执行流。

2.线程的优点

1.创建新线程的成本远低于创建新进程。

2.与进程切换相比,线程切换需要较少的操作系统资源。

3.线程比进程占用更少的资源。

4.它们能有效地利用多处理器并行处理的能力。

5.在等待缓慢的I/O操作时,程序还可以进行其他计算任务。

6.在多处理器系统中,计算密集型应用通过分解计算任务到多个线程中来运行。

7.I/O密集型应用通过重叠I/O操作来提升性能,允许线程同时等待多个I/O操作。

3.线程的缺点

a.增加额外开销

计算密集型线程,若很少受外部事件阻塞,通常不能与其他线程共享同一处理器。当计算密集型线程的数量超过可用处理器时,可能会导致显著的性能损失。这种性能损失主要是由于增加了额外的同步和调度开销,而可用资源保持不变。

b.线程安全

多线程编程需要更全面和深入的考量。在多线程程序中,由于时间分配上的微小偏差或共享了不应共享的变量,可能会产生不良影响,这意味着线程之间缺乏必要的保护。

c.缺乏访问控制

进程是访问控制的基本单位。在一个线程中调用某些操作系统函数可能会影响整个进程。

d.编程难度提高

编写和调试多线程程序比单线程程序更加困难。

e.线程异常

如果单个线程出现除零错误或野指针问题导致崩溃,整个进程也会因此崩溃。线程是进程的执行分支,一旦线程发生异常,就相当于进程发生异常,这将触发信号机制并终止进程。一旦进程终止,该进程内的所有线程也将随之退出。

二、Linux下进程与线程的区别

进程是资源分配的基本单位 线程是调度的基本单位

1.资源的区别

线程共享进程的数据,同时也有它们自己独立的数据部分:

线程ID

一组寄存器

errno

信号屏蔽字

调度优先级

进程中的多个线程共享同一个地址空间,因此Text Segment、Data Segment都是共享的。如果定义了一个函数,它可以在所有线程中被调用;如果定义了一个全局变量,它也可以在所有线程中被访问。除此之外,所有线程还共享其他进程资源和环境:

文件描述符表

每种信号的处理方式

当前工目录

用户id和组id

2.切换开销

从一个进程切换到另一个进程,需要保存当前进程的状态并恢复新进程的状态,这个过程称为上下文切换。而线程切换的开销较小,因为线程共享相同的地址空间,不需要改变地址空间的映射关系。

3.同步与通信

进程之间的通信需要进行进程间通信(IPC),如管道、消息队列等,这些方法效率较低。而线程之间的通信可以直接通过共享内存、全局变量等方式进行,效率较高。

4.单元性

进程是独立的执行单位,一个进程崩溃不会影响其他进程。而线程共享同一个进程的资源,一个线程崩溃可能导致整个进程崩溃。

三、Linux线程控制

1.POSIX线程库

POSIX线程库(POSIX Threads)也被称为pthread库,是一套线程创建、同步、调度和管理的标准接口,定义了在多线程程序中使用线程的API和语义。POSIX线程库通常用于UNIX和类UNIX操作系统(如Linux)上。

POSIX线程库的主要特点包括:

  1. 标准化接口: POSIX线程库定义了一套标准的线程操作接口,包括线程的创建、销毁、同步等操作,使得多线程程序能够以跨平台的方式编写。

  2. 线程管理: POSIX线程库提供了对线程的管理功能,包括线程创建、退出、同步、互斥锁、条件变量、信号量等。

  3. 线程调度: POSIX线程库定义了线程的调度接口,可以设置线程的调度策略、优先级和调度参数。

  4. 线程同步: 提供了各种线程同步的机制,确保多个线程之间的协作和同步。

在使用POSIX线程库时,需要包含 <pthread.h> 头文件,并链接 -lpthread 库。

2.创建线程

使用pthread_create()函数

函数声明:

参数解析

thread:返回线程ID

attr:设置线程的属性,attr为NULL表示使用默认属性

start_routine:是个函数地址,线程启动后要执行的函数

arg:传给线程启动函数的参数

返回值:成功返回0;失败返回错误码

错误检查:

传统的一些函数在成功时返回0,在失败时返回-1,并且会对全局变量errno赋值以指示错误类型。

而pthreads函数在出错时不会设置全局变量errno(尽管大多数其他POSIX函数会这样做),它们会通过返回值来传递错误代码。

pthreads也提供了线程内的errno变量,以便支持其他依赖errno的代码。但对于pthreads函数的错误处理,建议通过检查返回值来判断,因为这比读取线程内的errno变量要节省开销。

示例代码:

#include <iostream>
#include <unistd.h>
#include <pthread.h> 
#include "Thread.hpp"

void *Printf(void *arg)
{
    
    printf("wohu!, 我是一个线程...\n");
    sleep(2);   
    
}



using namespace std;
int main()
{
    pthread_t pid;
    int ret = pthread_create(&pid, nullptr, Printf, nullptr);
    if(ret != 0)
    {
        cerr << " 线程创建错误" << endl;
        exit(EXIT_FAILURE);
    }
    pthread_join(pid,nullptr);


    return 0;
}

3、线程ID与虚拟地址空间的关系

pthread_create函数生成一个线程ID,存储在第一个参数所指的地址。这个线程ID与之前提到的不同。

先前提到的线程ID是进程调度的一部分。由于线程是轻量级的进程,是操作系统调度的基本单位,因此它需要一个唯一的数值来标识。

pthread_create函数的第一个参数指向一个虚拟内存单元,这个内存单元的地址就是新线程的线程ID,这属于NPTL线程库的范围。线程库的操作都是基于这个线程ID进行的。

NPTL线程库还提供了pthread_self函数,用于获取线程自身的ID。

对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。

4.线程终止

如果需要只终止某个线程而不终止整个进程,可以有三种方法:

1. 从线程函数中返回。这种方法不适用于主线程,因为从main函数中返回等同于调用exit。

2. 线程可以通过调用pthread_exit来结束自己。

3. 一个线程可以通过调用pthread_cancel来终止同一进程中的另一个线程。

5.线程等待

为什么需要线程等待?

已退出的线程,其空间未被释放,仍在进程地址空间内。

新创建的线程将不会复用之前退出线程的地址空间。

使用pthread_join来进行线程等待

调用该函数的线程会挂起等待,直到标识为thread的线程终止。thread线程的终止方式不同,通过pthread_join获得的终止状态也不同,具体如下:

1. 如果thread线程通过return返回,value_ptr所指向的单元中存放的是thread线程函数的返回值。
2. 如果thread线程被其他线程以pthread_cancel调用异常终止,value_ptr所指向的单元中存放的是常量PTHREAD_CANCELED。
3. 如果thread线程通过调用pthread_exit自行终止,value_ptr所指向的单元中存放的是传递给pthread_exit的参数。
4. 如果不关心thread线程的终止状态,可以向value_ptr参数传递NULL值。

6.线程分离

默认情况下,新创建的线程是可连接的。线程结束后,必须执行pthread_join操作以释放资源,否则可能导致系统资源泄露。如果不需要线程的返回值,join操作可能显得多余。在这种情况下,我们可以设置线程在退出时自动释放其资源。

使用pthread_detach进行线程分离

int pthread_detach(pthread_t thread);

也可以自己分离

pthread_detach(pthread_self());

四、Linux线程互斥

1.线程互斥的前置概念

临界资源:指多线程执行流中共享的资源。

临界区:是指在每个线程中访问临界资源的那部分代码。

互斥:确保任何时刻只有一个执行流能进入临界区访问临界资源,起到保护临界资源的作用。

原子性:指的是不可被任何调度机制中断的操作,这种操作只有完成或未完成两种状态。

2.互斥锁mutex

多个执行流同时访问同一个临界资源会带来一些问题,这个时候就需要用到锁。

2.1比如说下面这个简单的卖票场景:

四个线程同时卖100张票

#include <iostream>
#include <unistd.h>
#include <pthread.h> 
#include "Thread.hpp"
int t = 100;

void *tick(void *arg)
{
   
    while(1)
    {
        if(t < 0)
        {
           break;
        }
        else
        {
            usleep(1000);
            printf("线程%d卖: %d\n", pthread_self(), t);
            t--;
        }
    }
    return nullptr;
}

int main()
{
    pthread_t t1,t2,t3,t4;
    pthread_create(&t1, nullptr, tick, nullptr);
    pthread_create(&t2, nullptr, tick, nullptr);
    pthread_create(&t3, nullptr, tick, nullptr);
    pthread_create(&t4, nullptr, tick, nullptr);
    pthread_join(t1,nullptr);
    pthread_join(t2,nullptr);
    pthread_join(t3,nullptr);
    pthread_join(t4,nullptr);


    return 0;
}

运行结果:

为什么会出现这样的情况?

1.if 语句判断条件为真以后,代码可以并发的切换到其他线程

2.usleep 这个模拟漫长业务的过程,在这个漫长的业务过程中,可能有很多个线程会进入该代码段

3.t-- 操作本身就不是一个原子操作

t--的汇编代码

可以看到t--是由三条汇编代码组成的,所以t--不是原子的。

要解决上述问题,需确保三个条件得到满足:

1.代码必须实现互斥,当一个线程进入临界区执行时,其他线程不得进入此临界区。

2.若多个线程同时请求执行临界区代码,而且临界区内没有线程在执行,则只能让一个线程进入该临界区。

3.若线程未在临界区内执行,则不应阻止其他线程进入临界区。

本质上就是加锁。

2.2互斥锁的接口

2.2.1初始化mutex

1.静态初始化

把mutex定义到全局区

2.使用init函数

2.2.2销毁mutex

使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁

2.2.2mutex加锁和解锁

成功返回0,失败返回错误码

调用 pthread_ lock 时,可能会遇到以下情况:

当互斥量处于未锁定状态时,该函数会锁定互斥量,并返回成功。

如果在调用函数时,互斥量已被其他线程锁定,或者有其他线程也在申请互斥量但未能成功竞争到,那么pthread_mutex_lock调用将会阻塞(即执行流被挂起),直到互斥量被解锁。

改进之前的代码:

加上锁

#include <iostream>
#include <unistd.h>
#include <pthread.h> 
#include "Thread.hpp"
int t = 100;

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

void *tick(void *arg)
{
   
    while(1)
    { 
        pthread_mutex_lock(&mtx);
        if(t < 0)
        {
            pthread_mutex_unlock(&mtx);
           break;
        }
        else
        {
            usleep(1000);
            printf("线程%d卖: %d\n", pthread_self(), t);
            t--;
            pthread_mutex_unlock(&mtx);
        }
    }
    return nullptr;
}

int main()
{
    pthread_t t1,t2,t3,t4;
    pthread_create(&t1, nullptr, tick, nullptr);
    pthread_create(&t2, nullptr, tick, nullptr);
    pthread_create(&t3, nullptr, tick, nullptr);
    pthread_create(&t4, nullptr, tick, nullptr);
    pthread_join(t1,nullptr);
    pthread_join(t2,nullptr);
    pthread_join(t3,nullptr);
    pthread_join(t4,nullptr);


    return 0;
}

运行结果:

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

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

相关文章

每日OJ题_DFS解决FloodFill⑤_力扣417. 太平洋大西洋水流问题

目录 力扣417. 太平洋大西洋水流问题 解析代码 力扣417. 太平洋大西洋水流问题 417. 太平洋大西洋水流问题 难度 中等 有一个 m n 的矩形岛屿&#xff0c;与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界&#xff0c;而 “大西洋” 处于大陆的右边界和下…

题目----力扣--移除链表元素

题目 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5]示例 2&#xff1a; 输入&…

2024年4月17日华为春招实习试题【三题】-题目+题解+在线评测,2024.4.17,华为机试

2024年4月17日华为春招实习试题【三题】-题目题解在线评测 &#x1f52e;题目一描述&#xff1a;扑克牌消消乐输入描述输出描述样例一样例二Limitation解题思路一&#xff1a;模拟&#xff0c;遇到连续3张相同牌号的卡牌&#xff0c;直接删除解题思路二&#xff1a;栈解题思路三…

【备战软考(嵌入式系统设计师)】08 - 多媒体技术信息安全

多媒体技术 这内容比较杂&#xff0c;而且跟咱嵌入式的关系不大&#xff0c;但是软考里会考一些&#xff0c;下面我就结合我已经刷过的一千多道往年真题概括总结一下常考的知识点。 媒体分类 首先媒体分为五类&#xff1a; 感觉媒体&#xff0c;让人直接感觉得到的媒体&…

热敏电阻怎么进行性能测试?并以LabVIEW为例进行说明

过程也可用于执行热敏电阻测量。RTD和热敏电阻遵循非常相似的功能原理&#xff0c;测量步骤与下面提供的步骤相同。有关热敏电阻的更多信息&#xff0c;请参阅本文档。 查找设备引脚排列 在连接任何信号之前&#xff0c;请找到您的设备引脚排列。 打开NI MAX并展开设备和接口。…

【Java笔记】多线程:一些有关中断的理解

文章目录 线程中断的作用线程的等待状态WAITINGTIMED_WAITING 线程从等待中恢复 java.lang.Thread中断实现相关方法中断标识interrupted 一些小练习Thread.interrupt() 只唤醒线程并修改中断标识sleep() 清除中断状态标识 Reference 线程中断的作用 线程中断可以使一个线程从等…

关于2024年上半年软考考试批次安排的通告

按照《2024年计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试工作安排及有关事项的通知》&#xff08;计考办〔2024〕1号&#xff09;文件精神&#xff0c;结合各地机位实际&#xff0c;现将2024年上半年计算机软件资格考试有关安排通告如下&#xff1a; 一、考…

鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断

关于中断部分系列篇将用三篇详细说明整个过程. 中断概念篇 中断概念很多&#xff0c;比如中断控制器&#xff0c;中断源&#xff0c;中断向量&#xff0c;中断共享&#xff0c;中断处理程序等等.本篇做一次整理.先了解透概念才好理解中断过程.用海公公打比方说明白中断各个概念…

GORM 与 MySQL(一)

GORM 操作 Mysql 数据库&#xff08;一&#xff09; 温馨提示&#xff1a;以下关于 GORM 的使用&#xff0c;是基于 Gin 框架的基础上&#xff0c;如果之前没有了解过 Gin 可能略微困难。 GORM 介绍 GORM 是 Golang 的一个 orm 框架。简单说&#xff0c;ORM 就是通过实例对象…

京东工业优选商品详情API接口:解锁高效工业采购新体验

京东工业优选的商品详情API接口&#xff0c;允许开发者通过程序化的方式&#xff0c;快速获取平台上的商品详细信息。这些详细信息包括但不限于商品名称、价格、规格、库存、图片、评价等&#xff0c;为企业提供全方位的商品信息查询服务。 二、API接口的主要功能 实时查询&a…

如何查看慢查询

4.2 如何查看慢查询 知道了以上内容之后&#xff0c;那么咱们如何去查看慢查询日志列表呢&#xff1a; slowlog len&#xff1a;查询慢查询日志长度slowlog get [n]&#xff1a;读取n条慢查询日志slowlog reset&#xff1a;清空慢查询列表 5、服务器端优化-命令及安全配置 安…

DDR4 新功能介绍

DDR4(第四代双倍数据率同步动态随机存取内存)相较于其前代DDR3,引入了一些新的功能和改进,这些新功能有助于提高内存的性能、降低功耗以及增强系统的可靠性,包括VPP、DBI(Data Bus Inversion,数据总线翻转)和DMI(与LPDDR4相关)。以下是对这些功能的简要说明: 更高的…

Stable Diffusion:AI绘画的新纪元

摘要&#xff1a; Stable Diffusion&#xff08;SD&#xff09;作为AI绘画领域的新星&#xff0c;以其开源免费、强大的生成能力和高度的自定义性&#xff0c;正在引领一场艺术与技术的革命。本文旨在为读者提供Stable Diffusion的全面介绍&#xff0c;包括其原理、核心组件、安…

嵌入式学习——C语言基础——day15

1. 段错误调试 1.1 打印法 在可能出现错误的位置加入打印,前一句能够打印出来,后一句打印不出来,问题就可以定位到两次打印中间的代码 1.2 gbd调试法 1. 编译代码时加入-g选项 gcc filename.c -g 2. 使用gdb调试生成的代码 gdb a.out 3. gdb调试命令 l 查看…

突然断电,瀚高数据库启动失败

服务器临时断电后&#xff0c;数据库启动不起来 ps -ef|grep postgres 进到数据库的data目录下看下ls 看下 查看临时文件&#xff1a; ls -la /tmp 把这两个5866的文件改个名字张老师 加个bak就行 改完了pg_ctl start起一下

六、文件查找

一、文件查找 1.查找文件内容 ​ 命令&#xff1a;grep keywords /dir_path/filename 2.查找系统命令 ​ 命令&#xff1a;which command 3.查找命令及配置文件位置 ​ 命令&#xff1a;whereis command 4.find查找 ​ find $find_path -name|-type|-perm|-size|-atime…

HarmonyOS实战开发教程-如何开发一个2048游戏

今天为大家分享的是2048小游戏&#xff0c;先看效果图&#xff1a; 这个项目对于新手友友来说可能有一点难度&#xff0c;但是只要坚持看完一定会有收获。因为小编想分享的并不局限于ArkTs语言&#xff0c;而是编程思想。 这个游戏的基本逻辑是初始化一个4乘4的数组&#xff…

跟TED演讲学英文:4 pillars of college success in science by Freeman Hrabowski

4 pillars of college success in science Link: https://www.ted.com/talks/freeman_hrabowski_4_pillars_of_college_success_in_science Speaker: Freeman Hrabowski Date: February 2013 文章目录 4 pillars of college success in scienceIntroductionVocabularyTranscr…

休斯《公共管理导论》第5版/考研真题解析/章节题库

第一部分 考研真题精选 一、概念题二、简答题三、论述题四、案例分析题第二部分 章节题库 第1章 一个变革的时代第2章 政府的角色第3章 传统的公共行政模式第4章 公共管理第5章 公共政策第6章 治 理第7章 问 责第8章 利害关系人和外部环境第9章 管制、外包和公共企…

有哪些软件可以使用云渲染?

随着技术的发展&#xff0c;云渲染已成为动画制作人员与设计师重要的渲染助手。它可结合云端强大的计算机能力&#xff0c;帮助渲染人员高速的完成渲染任务&#xff0c;大幅度节省时间和本地计算资源。它们以用户友好的界面、强大灵活的渲染能力&#xff0c;满足了各类专业渲染…