Linux线程

1.线程概念

1.1什么是线程

线程就是进程的一条执行流,是CPU的调度的基本单位,,这个执行流在Linux下是通过pcb实现的,共享了进程的大部分资源。相比进程更加轻量化,所以线程也被称为轻量级进程。线程在进程内部运行的,是进程内部的一个控制序列。
在这里插入图片描述

在Linux中没有真正的线程,而是由进程模拟的,在Linux中的所有执行流,都叫做轻量级进程。所以在Linux中也没有真正意义上的线程相关的系统调用。

1.2线程优点

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

1.3线程缺点

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

1.4 线程异常

  • 单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃
  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出

1.5 进程和线程的区别

  1. 进程是资源分配的最小单位,线程是CPU调度的最小单位
  2. 进程拥有独立的系统资源,在同一个进程中,线程共享该进程的大部分系统资源
  3. 一个进程崩溃,不会对其他进程产生影响;一个线程崩溃会对同一个进程内的其他线程产生影响
  4. 进程在创建、切换、销毁会比线程开销大
  5. 进程间通信比线程间通信复杂

线程独有:线程ID(用来区分线程)、程序计数器(保存即将被执行下一条指令的地址)、一组寄存器(线程执行所保存的上下文环境)、栈

2 线程和进程的关系

在这里插入图片描述

3 线程控制

3.1 创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(start_routine)(void), void *arg);
参数
thread:返回线程ID
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数 返回值:
成功返回0;失败返回错误码

3.2 线程等待

为什么需要线程等待?

  1. 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
  2. 创建新的线程不会复用刚才退出线程的地址空间。

int pthread_join(pthread_t thread, void **value_ptr);
参数
thread:线程ID
value_ptr:它指向一个指针,后者指向线程的返回值 (线程退出的退出码)
返回值:成功返回0;失败返回错误码

3.3 线程终止

终止某个线程而不是整个进程的三种方法

  1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit
  2. 线程可以调用pthread_ exit终止自己
  3. 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程

void pthread_exit(void *value_ptr);
参数:value_ptr:value_ptr不要指向一个局部变量
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)

pthread_cancel函数
功能:取消一个执行中的线程
原型 int pthread_cancel(pthread_t thread);
参数 thread:线程ID 返回值:
成功返回-1 ;失败返回错误码

注意:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配。因为当其它线程得到这个返回指针时线程函数已经退出了

3.4 线程分离

一般情况下线程是必须被等待的,就如同子进程被等待一样,线程可以不用join,但是需要将线程进行分离。

3.5 线程互斥

3.5.1 线程间互斥的相关背景

  • 临界资源:多线程执行流共享的资源叫做临界资源
  • 临界区:每个线程内部,访问临界资源的代码,就叫做临界区
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常是对临界资源起到保护作用
  • 原子性:不可被分割,该操作只有两态,要么完成要么未完成

3.5.2 互斥量mutex

  • 在大部分情况下,线程使用的数据都是局部变量的,变量的地址空间在线程栈空间内,这种情况中,变量归属单个线程,其他线程无法获得该变量
  • 共享变量可以通过数据共享完成线程之间的交互
    在这里插入图片描述

出现上述代码问题是因为,该操作不是原子性的,而是执行对应的三条汇编指令
load :将共享变量ticket从内存加载到寄存器中
update : 更新寄存器里面的值,执行-1操作
store :将新值,从寄存器写回共享变量ticket的内存地址

解决方法:当代码进入临界区时,不允许其他线程进入该临界区。所以就可以加锁。如图所示:
在这里插入图片描述

4 可重入&线程安全

4.1 概念

  • 线程安全:多个线程并发同一段代码时,不会出现不同的而结果。常见对全局变量或者静态变量进行操作,并且没有锁保护的情况下,会出现该问题。
  • 重入:同一个函数被不同的执行流调用,当前一个流程还没执行完,就有其他的执行流再次进入,我们称之为重入。一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数称为可重入函数。

4.2 线程不安全的情况

  • 不保护共享变量的函数
  • 函数状态随着被调用发生变化的函数
  • 返回指向静态变量的指针的函数
  • 调用线程不安全当函数的函数

4.3 线程安全的情况

  • 每个线程对全局变量或者静态变量只有读取的权限没有写入的权限,一般来说这些线程是安全的
  • 类或者接口对于线程来说是原子操作
  • 多个线程之间的切换不会导致该接口的执行结果存在二义性

4.4 不可重入情况

  • 调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的
  • 调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构
  • 可重入函数体内使用了静态的数据结构

4.5 可重入情况

  • 不使用全局变量或静态变量
  • 不使用用malloc或者new开辟出的空间
  • 不调用不可重入函数
  • 不返回静态或全局数据,所有数据都由函数的调用者提供
  • 使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据

4.6 可重入与线程安全联系

  • 函数是可重入的,那就是线程安全的
  • 函数是不可重入的,那就不能由多个线程使用,有可能引发线程安全问题
  • 如果一个函数中有全局变量,那么这个函数既不是线程安全也不是可重入的

4.7 可重入与线程安全区别

  • 可重入函数是线程安全函数的一种
  • 线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
  • 如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会产生死锁,因此是不可重入的。

5 死锁

5.1 死锁概念

死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放的资源而处于一种永久等待的状态

5.2 死锁的四个必要条件

  1. 互斥条件:一个资源每次只能被一个执行流使用
  2. 请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺
  4. 循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系

6 生产者消费者模型

在这里插入图片描述
生产者消费者模型讲解

7 线程同步

7.1 什么是同步

同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,就叫做同步。

8 POSIX信号量

信号量和信号以及条件变量是不一样的。
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。本质是一个计数器,描述临界资源中资源数目的计数器。
信号量存在的价值:同步和互斥、更细粒度的临界资源的管理。
申请信号量:P操作;申请信号量的本质就是:让计数器–;
释放信号量:V操作;释放信号量的本质就是:让计数器++;
信号量本质也是一种临界资源,信号 量PV操作必须是原子的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值