【Linux】线程互斥

1. 背景概念

多线程中,存在一个全局变量,是被所有执行流共享的
根据历史经验,线程中大部分资源都会直接或者间接共享
只要存在共享,就可能存在被并发访问的问题

假设有一间教室被学校内的所有社团共享的,所以这个教室属于公共资源,
有可能当一个社团在这个教室举办活动时,别的社团也想占用这个教室
即 一个公共资源被并发访问了
为了保证访问时不能被别人去抢走,所以就把门窗都关上,直到访问完,才让别人进来
即 发生互斥

为了保证对应的共享资源的安全,用某种方式将共享资源保护起来,这部分共享资源称之为临界资源

访问临界资源执行的代码 称之为 临界区

2. 证明全局变量做修改时,在多线程并发访问会出问题

在这里插入图片描述
创建一个全局变量 tickets 作为票数,并创建4个线程,
分别调用自定义函数 thread_run 来对tickets进行–操作 ,直到tickets的值<0才结束
在这里插入图片描述
创建一个全局变量 tickets 作为票数,并创建4个线程,
分别调用自定义tickets变为负数 ,是不合理的
在这里插入图片描述
在我们设计中,若ticjets<0就会直接break退出,只有当tickets>0时才会打印出对应tickets的值

假设 tickets==1 ,此时有 a b c d 4个线程
当线程a 通过判断 进入 if语句中的 sleep中时 ,被上下文保护了
线程b 也执行判断 进入 if语句,继续向下执行完 tickets-- ,
此时的tickets的值为0,CPU就会再次执行还未执行完的线程a 的剩余步骤,tickets-- 即 0-1 =-1

3. 锁的使用

为了避免全局变量 出现负数的情况,所以引入 加锁 用于保证共享资源的安全

pthread_mutex_init
在这里插入图片描述
第一个参数 为 互斥锁,对该锁进行初始化,初始化该锁处于工作状态
第二个参数 为属性 一般设置为 nullptr

一般有两种初始化方案

第一种,锁为全局变量 ,直接用PTHREAD_MUTEX_INITIALIZER,对锁进行初始化
后面就不用 通过pthread_mutex_destroy 对其进行摧毁

第二种,若锁为局部变量,就必须调用pthread_init 进行初始化,用完后也必须调用 pthread_destroy 进行销毁

输入 man pthread_mutex_lock 加锁
输入 man pthread_mutex_unlock 解锁

具体操作实现

设置为全局锁

若锁为全局变量,可以选择在主函数中初始化锁 与销毁锁
在这里插入图片描述

设置为局部锁

在这里插入图片描述

4. 互斥锁细节问题

  1. 访问同一个临界资源的线程,都要进行加锁操作保护,而且必须加同一把锁
    (每一个线程在访问临界资源之前都要先加锁)

  2. 每一个线程访问临界区之前,得加锁,加锁本质是给临界区加锁
    加锁粒度尽量要细一些

  3. 线程访问临界区的时候,需要先加锁 -> 所有线程都必须要先看到同一把锁 -> 锁本身就是公共资源
    ->锁如何保证自身安全? ->加锁和解锁本身就是原子的
    (原子性:要么就不加锁,要加锁就加成功)
    锁的申请是安全的,就可以保证锁保护的资源本身也是安全的

  4. 临界区可以是一行代码,也可以是一批代码
    访问全局资源时,可能会存在多并发访问的问题

切换会有影响吗?
加锁在临界区内,加锁后,对临界区代码进行任意切换会不会影响数据出现安全方面的问题?
不会,我不在期间,其他人没有办法进入临界区,因为无法成功申请到锁,锁被我拿走了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值