Linux多线程——线程互斥与同步和其他概念

文章目录

线程互斥

我们之前介绍过互斥的概念,但没有介绍Linux中线程互斥的操作

互斥存在的必要性是因为访问共享资源时,有可能被CPU换下,这样就会产生bug

例如说我们上一篇中说过的抢票,我们虽然设置的是当ticket小于等于0时结束线程

但是当五个线程几乎同时进入这个判断,就会导致过量运行

主要是因为这些操作并非原子的,不是原语

要解决这个问题就需要互斥锁

互斥锁的使用

互斥锁的使用一般分为四个步骤

  1. 初始化互斥锁
  2. 临界区前加锁
  3. 临界区后解锁
  4. 用完后销毁
初始化互斥锁

这里有两个方法,第一个是静态分配

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

第二个是动态分配

int pthread_mutex_init(pthread_mutex_t* restrict mutex, const pthread_mutexattr_t* restrict attr)

第一个是要初始化的互斥量,我们在调用之前声明一共传入即可,第二个我们传入NULL

加锁和解锁

int pthread_mutex_lock(pthread_mutex_t* mutex)

int pthread_mutex_unlock(pthread_mutex_t* mutex)

当原来的互斥量没有被加锁,此时加锁就会成功

当互斥量已经被上锁了,这个线程就会被阻塞,等待互斥量解锁

销毁互斥锁

静态的互斥锁不需要销毁

已经加锁的互斥量不允许被销毁

已经销毁的互斥量,要确保以后不会再被用到

int pthread_mutex_destory(pthread_mutex_t* mutex)

这里互斥锁的库要直接使用也是不方便的,我们同样可以给其封装成类会好用很多

线程死锁

死锁指的是一个线程或者几个线程互相阻塞等待,没有任何一个线程在运行

要避免陷入死锁可以尝试破坏以下几个条件

  • 互斥条件
  • 请求与保持:一个执行流被阻塞时依然占据其保持的其他资源
  • 不剥夺条件:一个执行流获得的资源在未使用完之前不能被强行剥夺
  • 循环等待条件

线程安全与可重入

线程安全指的是在多个线程并发执行同一段代码时,不会出现不同的结果

这里主要指的是对于全局变量和静态变量

重入指的是,同一个函数被不同的执行流调用时,当一个执行流还没有执行完成,另一个执行流就再次进入的情况。一个函数可重入就说明可以同时搭载多个执行流而不出现bug,否则就是不可重入函数

实际上可重入的条件比线程安全更加严格

下面的情况出现,就说这个函数不可重入,否则会出现bug

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

一般来说,函数可重入,那么线程一定是安全的,如果函数不可重入,那么就不允许多线程并发使用

线程同步

一方面是因为有可能资源被一个线程霸占,另一方面我们可能希望执行流有先后的执行顺序

同步就是让线程的执行流有先后的执行顺序

竞态条件指的是,因为时序问题,导致的程序问题

线程同步的接口

与互斥类似,线程同步也分为四部

  1. 初始化条件变量
  2. 利用条件变量等待资源就绪
  3. 资源就绪后唤醒线程来访问
  4. 使用后销毁条件变量
初始化条件变量
c 复制代码
pthread_cond_t cond;//定义变量后再初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

cond是要初始化的条件变量

attr传入NULL

利用条件变量等待资源就绪
c 复制代码
int pthread_cond_wait(pthread_cond_t* restrict cond, pthread_mutex_t* restrict mutex)

要在cond这个条件变量上等待,mutex是互斥量

进程资源等待的前提是,拿到锁进入临界区,所以wait函数需要条件变量和互斥锁

唤醒等待
c 复制代码
int pthread_cond_broadcast(pthread_cond_t* cond);
int pthread_cond_signal(pthread_cond_t* cond);

第一个是唤醒所有线程,是广播

第二个是唤醒某一个线程

销毁
c 复制代码
int pthread_cond_destory(pthread_cond_t* cond);
相关推荐
HLC++9 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室10 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy13 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕13 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫14 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生15 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1116 小时前
linux基础IO
linux·运维·服务器
BelongPanda18 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯18 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983418 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器