80-多线程互斥与同步

上一个实验中的抢票错误问题,在于两个线程针对同一个变量进行读写而导致。

1. 资源竞争导致的问题

以抢票问题为例,下面具体分析一下两个线程的执行情况。见图 1.


这里写图片描述
图1 抢票问题

有关图 1 的说明:

  • 蓝色框和红色框分别表示不同的线程。
  • 实线表示真正的执行流程,而线程是无法感知到其它线程的存在,故线程自己认为自己是按照虚线流程来走的。(有关线程切换请参考专题《多线程切换与调度》
  • 变量 t 是线程自己的局部变量,保存在线程自己的运行栈上。不同线程有各自的运行栈,所以两个线程的变量 t 并不是同一个 t,分别用蓝红颜色表示。
  • tickets 是一个全局变量,保存在全局数据区。被初始化为 3,两个线程访问到的 tickets 都是同一份(tickets 被称为竞态资源).

根据图 1 我们很快就能知道原因:因为两个线程对全局变量 tickets 操作需要 3 个步骤,当两个线程对 tickets 的操作产生交叉时,就会产生错误。

如果对 tickets 仅仅只有读而没有写,即使产生步骤上的交叉也不会有问题。但是如果存在写操作,就很容易导致数据的不一致。

为了解决此问题我们希望线程 A 在执行这 3 个动作的时候,线程 B 就不允许执行这 3 个动作。此解决方案,称为多线程互斥。

2. 多线程互斥

从第 1 节的叙述中你应该可以理解互斥所要做的事,即我做某件事的时候你不允许做,而你做某件事的时候也不允许我做。

这个问题如果我们不使用信号量或者 pthread 提供的接口将会很难解决。当然你完全可以自己写一个程序来避免此问题。

后面,会介绍 pthread 的互斥接口来达到多线程互斥的目的,也就是 pthread 提供的几把锁:

  • 互斥锁 mutex
  • 读写锁 rwlock
  • 自旋锁 spinlock

不要被这些名字吓倒,实际上,这些锁完成的功能都很类似,只是使用的场景不太一样。

好了,可能你还明白“锁”的概念。举个例子,火车上有公厕,当有人用的时候,门上的锁会显示“有人”两个字,没人用时,会显示“无人”。别人干活的时候,你肯定是不能进去的是吧……

所以,“锁”是有它的状态的,即被锁住的状态和打开的状态。而 pthread 线程库中提供的锁也是有状态的,和火车上那个差不多。

3. 多线程同步

同步与互斥稍稍不同,具体差别在于两个字——顺序。意思是说,只有当我做完了某件事,你才能做另一件事。比方说,只有你做完作业了,我才能给你批改。

当然实现这样的功能一般有两种方式:

  • 你做完作业了,然后你打电话通知我,我再去帮你修改
  • 我每隔一段时间打电话问你写完作业没,确认你写完了,我再去帮你修改

很明显第一种方式要好很多,因此 pthread 提供了条件变量来实现这个功能。这些将在后文中介绍。

4. 总结

  • 理解多线程产生的竞态问题
  • 理解互斥与同步的区别和联系
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值