Linux中的线程互斥

一、背景

多个线程能看到的资源叫共享资源,我们需要对资源进行保护,就要线程互斥。

1、背景一

CPU的运算分为逻辑运算和算术运算。以逻辑运算为例子:tickets = 1000; tickets > 0

2、背景二

在CPU中寄存器只有一套,但是寄存器中数据有多套。

数据是线程私有的,虽然放在了一个公共区域,但是线程的切换会带走自己的数据,回来的时候在恢复数据,所以数据仍然私有。

虽然数据是私有的,但是由于线程的切换会导致线程执行代码的过程是碎片的,对于一些全局的变量如果由于线程的切换执行代码导致被多个线程访问就会带来许多非法操作,这就是开头说的我们需要对共享资源进行保护,就要线程互斥。

二、线程互斥的实现:锁

1、基本知识

首先我们清楚程序员访问资源的方式就是代码,线程去执行代码就是访问资源。

所以访问不是共享资源的代码就是非临界区,访问共享资源的代码就是临界区。

对临界资源的保护就是对临界区代码的保护。锁就是用来保护临界区的。

2、锁的接口

(1)创建锁

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

用来定义局部锁,在栈上。(要调用函数销毁锁)

pthread_mutex_t:锁的数据类型

attr:锁的属性

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

用来定义全局锁(不用手动销毁)

(2)销毁锁

int pthread_mutex_destroy(pthread_mutex_t* mutex)

(3)加锁

int pthread_mutex_lock(pthread_mutex_t* mutex)

(4)解锁

int pthread_mutex_unlock(pthread_mutex_t* mutex)

3、代码案例

4、锁实现互斥的原理

未来会有很多线程访问代码,涉及临界区资源访问的代码只能同时只有一个线程访问,当多个线程竞争同一把锁时只有加锁成功的线程才能继续运行下面的代码也就是临界区,这样就保护了临界区。

注意

(1)加锁范围粒度要小。

(2)所有线程申请锁的前提是所有线程能看到同一把锁,锁本身就是共享资源。加锁的过程就必须是原子的。

(3)如果线程申请锁失败线程就会被阻塞。

(4)锁申请成功将执行临界区代码。

(5)申请锁成功执行临界区代码时可能会被CPU切走,但其他线程依然无法进入临界区。

申请锁成功本质就是 pthread_mutex_lock() 返回值,线程继续向后运行。

申请锁失败本质就是 pthread_mutex_lock() 不返回,线程阻塞。

不返回:申请锁的条件不成立,函数内部把线程状态改变使其阻塞。

锁被释放本质是 pthread_mutex_unlock() 在 pthread_mutex_lock() 内部重新唤醒,重新申请锁。

5、认识锁

我们用汇编伪代码解释锁

加锁过程:

(1)movb $0, &al           把寄存器al中的值置0

(2)xchgb %al, mutex    交换内存中锁的值和寄存器al的值

(3)如果交换来的值是1,就说明线程加锁成功,此时内存中锁的值是0,如果本线程不释放锁,下面线程交换来的都是0,实现只有一个线程访问临界区

(4)如果交换来的值是0,线程挂起等待

解锁过程:

(1)把内存中锁的值变成1,表示可以竞争锁了

(2)唤醒等待锁的线程竞争

三、补充知识

1、CPU中寄存器只有一套,被线程共享,但寄存器里面的数据是执行流上下文,属于执行流的私有数据。

2、CPU在执行代码时,一定有对应的执行载体,线程或进程

3、数据在内存中,被所有线程共享。

4、总结上述三点,得出结论:把数据从内存移动到寄存器,本质就是把数据从共享变成私有。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值