分析为什么加锁和解锁操作是原子的

临界资源:多线程执行流共享的资源就叫做临界资源。
临界区:每个线程内部,访问临界自娱的代码,就叫做临界区。
互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。

大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个线程,其他线程无法获得这种变量。但有时候,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完成线程之间的交互。多个线程并发的操作共享变量,会带来一些问题。
为了避免带来的问题,需要做到三点:

  • 代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
  • 如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临界区。
  • 如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。

要做到这三点,本质上就是需要一把锁。Linux上提供的这把锁叫互斥量。

1、我们需要先定义一个全局的互斥量:

pthread_mutea_t mutex;

2、在主函数中,我们需要将互斥量初始化:

pthread_mutex_init(&mutex, NULL);

3、在对临界区进行操作时,需要对互斥量加锁和解锁:

pthread_mutex_lock(&mutex);//加锁
pthread_mutex_unlock(&mutex);//解锁
返回值:成功返回0,失败返回错误号。

4、最后需要在主函数中销毁互斥量:

pthread_mutex_destroy(&mutex);

我们可以看到,互斥量(锁资源)必须被所有成员看到,所以锁也是临界资源,所以说加锁和解锁过程也应该是原子的,这个过程的原子性是怎么实现的呢?看下面两段伪代码。
pthread_mutex_lock函数实现的伪代码:

lock:
	movb $0, %al //把al清零
	xchgb %al, mutex //交换al和mutex的值
	if (al寄存器的内容 > 0)
		return 0;
	else
		挂起等待
	goto lock;

当线程1执行xchgb %al, mutex代码时,把mutex的值(1)和al的值(0)交换,假如这个时候线程1的时间片到了,线程2来了,则把此时al的值放到线程1的栈中便于线程1下次执行。线程2执行xchgb %al, mutex代码时,因为mutex的值已经是0,所以交换后al的值依然是0,结果if语句判断后挂起等待。所以只有线程1加锁成功,最后返回0。当线程1解锁之后,线程二结束挂起,执行goto lock;语句,跳到lock处重新申请锁。
如下图所示:
在这里插入图片描述

pthread_mutex_unlock函数实现的伪代码:

unlock:
	movb $1, mutex
	唤醒等待mutex的线程;
	return 0;

当线程1执行完movb $1, mutex语句时,假如说线程2开始执行了,这个时候无论线程2是之前在等待的还是未等待的线程,它申请锁操作都不会影响线程1了,因为这个时候线程1关于mutex的操作已经结束了。(主要是我们在代码中对mutex的操作代码只有一句)。

上面对两段伪代码的分析解释了为什么加锁和解锁操作是原子的。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值