Linux下线程相关知识总结

限时加码!20+主流AI编工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

1.线程的基本介绍

(1)线程的概述

线程与进程类似,也允许应用程序并发执行多个任务的一种机制。一个进程可以包含多个线程,同一程序中的所有线程共享同一份全局内存区域,线程之间没有真正意义的等级之分。同一个进程中的线程可以并发执行,如果处理器是多核的话线程也可以并行执行,如果一个线程因为等待I/O操作而阻塞,那么其他线程依然可以继续运行

(2)线程优于进程的方面

argv,environ
主线程栈
线程3的栈
线程2的栈
线程1的栈
共享函数库共享的内存
未初始化的数据段
初始化数据段
文本

.进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,因此必须采用一些进程间通讯,在进程之间交换信息
.调用fork()来创建进程代价相对较高
线程很好的解决了上述俩个问题
.线程之间能够方便,快速的共享信息,只需将数据复制到共享(全局或堆)变量中即可
.创建线程比创建线程通常要快10甚至更多,线程创建之所以快,是因为fork创建进程时所需复制多个属性,而在线程中,这些属性是共享的。

(3)创建线程

启动程序时,产生的进程只有单条线程,我们称之为主线程

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

新线程通过调用带有arg的函数开始执行,调用pthread_create()的线程会继续执行该调用之后的语句。

(4)终止线程

可以以如下方式终止线程的运行
.线程调用pthread_exit()
.线程start函数执行return语句并返回指定值
.调用pthread_cancel()取消线程
.任意线程调用了exit(),或者主线程执行了return语句,都会导致进程中的所有线程立即终止
pthread_exit()函数可以终止线程,且其返回值可由另一线程通过调用pthread_join()获得

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

调用pthread_exit()相当于在线程的start函数中执行return,不同之处在于,pthread_exit()可以在任何地方调用,参数retval指定了线程的返回值

(5)获取线程ID

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

线程ID在应用程序中主要有如下用途
.不同的pthreads函数利用线程ID来标识要操作目标线程。
.在具体的应用程序中,以特定线程的线程ID作为动态数据结构的标签,这颇有用处,既可用来识别某个数据结构的创建者或属主线程,又可确定随后对该数据结构执行操作的具体线程

函数pthread_equal()可检查俩个线程的ID是否相同

#include<pthread.h>
int pthread_equal(pthread_t t1,pthread_t t2);
//如果相同返回非0值,否则返回0

(6)连接已终止的线程

函数pthread_join()等待由thread表识的线程终止

#include<pthread.h>
int pthread_join(pthread_t thread,void **retval);
//返回0调用成功,否则失败

如果pthread_join()传入一个之前已然连接过的线程ID,将会导致无法预知的行为,当相同线程ID在参与一次连接后恰好为另一新建线程所重用,再度连接的可能就是这个新线程
若线程未分离,则就应该使用pthread_join()来连接线程,否则会产生僵尸线程

pthrea_join()函数的要点
.线程之间的关系是对等的,所以任意线程都可以调用pthread_join()来连接其他线程
.pthread_join()无法针对任意线程,只能连接单个线程

(6)线程的分离

默认情况下线程都是可连接的,但有时候,我们并不关心线程退出的状态,我们可以调用pthread_detach()并向thread参数传入指定线程的的标识符,将该线程标记为处于分离状态

#include<pthread.h>
int pthread_detach(pthread_t thread);
//返回0成功,否则失败

一旦线程处于分离状态,就不能在使用pthread_join()来获取其状态,也无法使其重返可连接状态

(7)在应用程序中如何来选择进程还是线程

.线程之间共享数据很简单,进程间的数据共享需要更多的投入
.创建线程要比创建进程块很多
.多线程编程时,需要确保调用线程安全的函数
.某个线程中的bug可能会危害进程中所有线程
.每个线程都在征用宿主进程中有限的虚拟地址空间
.在多线程应用中,需要小心使用信号
.除了数据,线程还可以共享文件描述符,信号处置,当前工作目录,以及用户ID和组ID

线程的同步

(1)保护共享变量访问:互斥量

线程的主要优势在于能够通过全局变量来共享信息,不过这种共享是有代价的。必须确保多个线程修改同一变量时,不会有其他线程也正在修改此变量,为避免线程更新时共享变量时所出现的问题,必须使用互斥量来确保同时仅有一个线程可以访问某项共享资源

(2)静态分配的互斥锁

互斥锁既可以像静态变量那样分配,也可以在运行时动态分配,互斥量属于pthread_mutex_t类型的变量,在使用之前必须对其初始化。对于静态分配的互斥量而言,可如下例所示,将PTHREAD_MUTEX_INITIALIZER赋给互斥量

pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;

1.加锁和解锁互斥量

初始化之后,互斥量处于未锁定状态。函数pthread_mutex_lock()可以锁定某一互斥量
而函数pthread_mutex_unlock()则可以将一个互斥量解锁

#include<pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//返回0成功,其他失败

要锁定互斥量,在调用pthread_mutex_lock()时需要指定互斥量,如果互斥量当前处于未锁定状态,则该调用将会立即返回,如果该互斥量已被其他线程锁定,那么该调用将会阻塞,直至互斥量被解锁
函数pthread_mutex_unlock()将解锁之前已遭调用线程锁定的互斥量

2.互斥量的性能

通常情况下,线程会花费更多的时间去做其他工作,对互斥量的加锁解锁相对要少的多,因此使用互斥量对大部分程序来说性能并无显著的影响

3.互斥量的死锁

当一个线程需要同时访问多个共享资源时,没个资源由不同的互斥索管理。当超过一个线程加锁同一组互斥量时,就有可能发生死锁。如下图所示
线程A
1.pthread_mutex_lock(mutex1);
2.pthread_mutex_lock(mutex2);
线程2
1.pthread_mutex_lock(mutex2);
2.pthread_mutex_lock(mutex1);
每个线程都成功的锁住一个互斥量,接着试图对以为另一线程锁定的互斥量加锁,就会一直等下去
要避免此类死锁问题,最简单的就是定义互斥量的层级关系

Linux线程 Linux线程的基础知识 阅读详情

相关推荐

机器视觉:9点标定的原理与实现

标定就是将机器视觉处理得到的像素坐标转换成实际项目中使用到的毫米坐标。简单说即使看看实际单位距离内有几个像素,如下图所示,10mm的距离内有222个像素,那像素坐标和实际的毫米坐标就有个比例关系了。

m0_49968063的博客 1万+

Linux线程详解

在一个序里的一个执行路线就叫做线程。更准确的定义是:线程是“一个进内部的控制序列”一切进都至少有一个执行线程线程在进内部运行,本质是在进地址空间内运行在Linux系统中,在CPU眼中,看到的PCB都要比传统的进更轻量化透过进虚拟地址空间,可以看到进的大部分资源,将进资源合理分配给每个执行流,就形成了线程执行流进的创建伴随着进控制块,进地址空间以及页表的创建,虚拟地址和物理地址就是通过页表建立映射的。

m0_72940975的博客 3677

流媒体弱网优化之路(NACK)——纯NACK方案的优化探索

流媒体学习之路(NACK)——纯NACK方案的最高性能 文章目录流媒体学习之路(NACK)——纯NACK方案的最高性能一、NACK简介二、Nack的理解2.1 一种补救策略2.2 什么时候要?2.3 要多少?2.4 怎么要?三、计算分析3.1 rtt强相关3.2 补包次数计算3.3 Nack的定时发送3.4 nack重传限制四、实验   近期在针对纯丢包场景做一些简单的探索实验,一个让我困扰的问题就是:不使用FEC而只是通过纯NACK进行补偿,到底能在实验环境下抵抗多少的丢包呢?每一次丢包补偿的最大时长

qw225967的博客 1万+

Linux系统】Linux线程详解

由上图可以很好地理解线程为什么是CPU调度的基本单位,在CPU看来,它只关心一个独立的执行流,无论进内部是一个还是多个执行流,CPU都是以task_struct为单位来调度的。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。在操作系统的的视角下,Linux下没有真正意义的线程,而是用进模拟的线程(LWP,轻量级进),所以Linux不会提供直接创建线程的系统调用,最多提供创建轻量级进的接口。个字节,也就是1MB。

fufufu_的博客 6739

linux线程全解

目录一、再论进1、进的挂起、阻塞和睡眠的区别:2、多进实现同时读取键盘和鼠标 一、再论进 1、进的挂起、阻塞和睡眠的区别: https://www.cnblogs.com/ck1020/p/6669661.html 2、多进实现同时读取键盘和鼠标 https://blog.csdn.net/u011508527/article/details/46878205 https://blog.csdn.net/jobbofhe/article/details/82192092 思路:创建子进,然后父

小嵌同学的博客 3114

Linux下线相关知识——学习笔记

一、线程基本概念 1、线程就是进中的执行路线,即进内部的控制序列,或者说是进的子任务(进就是正在运行的序,它是一个资源单位) 2、线程就是轻量级的,没有自己独立的内存资源,使用的是进的代码段、数据段、bss段、堆(注意:没有栈)、环境变量表、命令行参数、文件描述符、信号处理函数、工作目录、用户ID、组ID等资源。 3、线程拥有自己独立的栈,也就是有自己独立的局部变量。 4、一个进中可...

Love丶伊卡洛斯 402

Linux相关概念和易错知识点(28)(线程控制、Linux下线的底层)

成功返回0,错误返回错误码。

SGlow0708的博客 1048

Linux线程思维导图

lxf_style的博客 394

34.线程相关概念

Disappear_XueChao的博客 284

Linux线程全解:概念、操作、互斥与同步机制、线程池实现

如果说进是操作系统资源分配的基本单元,那么线程就是资源调度的基本单元,也是序执行的基本单元。我们可以把进看作工厂,资源就是工厂内部的原材料与各种机械设备,而线程就是工厂里的工人。因此如果进只有一个执行流,那它也是一个线程,称之为主线程,我们在进中创建线程其实就是在主线程下创建其他线程线程与进的关系如下图:说完了线程的概念,我们下面来说一下线的操作。1.线程池的初始化:线程池通过PoolInit创建多个工作线程,这些线程通过执行thr_start来不断地获取并处理任务。2.任务队列。

谁在夜里看海.的博客 5434

Linux线程

线程是轻量级的进(LWP:light weight process),在Linux环境下线的本质仍是进。在计算机上运行的序是一组指令及指令参数的组合,指令按照既定的逻辑控制计算机运行。操作系统会以进为单位,分配系统资源,可以这样理解,进是资源分配的最小单位,线程是操作系统调度执行的最小单位。

qq_55882840的博客 1952

Linux线程线程的创建,等待,终止,分离)

在OS书籍中,线程的概念通常是这样的:线程是在进内部运行的一个执行分支(执行流),属于进的一部分,粒度比进更加细,更加轻量化。通过这段话我们知道,线程与进的比是n:1的,在其他的操作系统中,由于线程的数量较多,OS需要对线程管理起来,就会存在先描述,后组织这一方式来管理线程。但是在Linux系统下,并不是这样管理线程的。

Liufan____的博客 736

linux下的线程

线程是轻量级的进,在linux环境下,它的本质仍然是进。操作系统会以进为单位分配分配资源。总的来说,进是分配资源的最小单位,而线程是操作系统进行调度的最小单位。

m0_74409155的博客 718

linux】学习 线程函数

号用pid_t数据类型表示,是一个非负整数 线程号用phread_t数据类型表示,linux使用无符号长整数表示。有的系统在实现phread_t的时候用一个结构体表示,所以在可移植的操作系统实现不能把它作为整数处理。线程也有线程号,线程号不唯一 只在它所属的进环境中有效。粗略认为一个系统调用 进入内核 即为一个取消点。处于分离状态的线程不能join(资源回收)线程调用pthread_exit退出线程。join是获取状态 分离立马失去状态。线程可以被同一进中的其他线程取消。线程从执行函数中返回。

weixin_49157161的博客 203

Linux】详解线程第一篇——由单线程到多线程的转变

从进到轻量级进的转变。线程介绍,以及Linux下的“线程”讲解,包含代码示例。

You don't have the guts to be what you wanna be. 989

Linux系统编——线程

之前的文章中我们已经对进相关的概念做了认识,从创建进、子进,进回收、进替换等,由于我们之前对于知识框架的不熟悉,为了方便我们的理解学习,我们在之前的学习中没有做到深挖细节和深入理解,对之前的进内容的有些部分做了简单的抽象,接下来我们学习的是比进粒度更细的一个概念——线程。在这部分内容中,我们除了学习主线的内容外,还会对之前的內容稍作补充和修改,这都是会在文章中提到的。资源共享:同一个进中的所有线程共享该进的资源,包括全局变量、堆栈和文件描述符。这使得线程之间的通信和数据交换更加高效。

学习日记 1154

Linux线程互斥{线程间的互斥相关背景概念/锁的相关问题/锁的原理/可重入VS线程安全}

加锁/解锁/锁的原理/可重入/线程安全。

Ape's IT Blog 1175

Linux - 什么是线程线程的操作

什么是线程:线程(Thread)是操作系统能够进行运算调度的最小单位. 它被包含在进之中, 是进中的实际运作单位. 一个进可以包含多个线程.进 : 线程 == 1 : n (n >= 1).进是系统分配资源的基本单位.线程则是系统调度的基本单位.在 Linux 中, 线程又被称为轻量级进. 因为线程不必再进行空间的分配. 只需要对新创建的线程进行初始化 (创建线程的PCB即可).

m0_74506452的博客 1116

linux系统】线程线程TCB+线程同步和互斥+线程安全)

需要注意的是,__thread 关键字是 GCC 的扩展语法,虽然在大多数情况下可以正常工作,但并不是 C 标准的一部分,因此在一些不支持 GCC 扩展语法的编译器中可能无法使用。在 C11 标准中引入了 _Thread_local 关键字,用于实现线程局部存储,具有类似的功能,而且是标准化的语法。

ProcedureStone的博客 1194
上一篇: TCP/IP详解学习笔记--TCP的坚持和保活定时器
下一篇: Linux下文件的阻塞与非阻塞对部分系统调用的影响
Shreck66
博客等级 码龄11年 118粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值