Day 56 同步

1.同步概念:

所谓同步,即同时起步,协调一致。不同的对象,对 同步 的理解方式各有不同。如,设备同步,是指在两个设备之间规定一个共同的时间参考 : 数据库同步,是指让两个或多个数据库内容保持一致,或者按 需要部分保持一致 : 文件同步,是指让两个或多个文件夹里的文件保持一致。
2.线程同步:
同步即协同步调,对公共区域数据按预定的先后次序访问,防止数据混乱。
线程同步,指一个线程发出某一功能调用时, 在没有得到结果之前,该调用不返回。同时其它线程为保证数据一致性,不能调用该功能。
同步 的目的,是为了避免数据混乱,解决与时间有关的错误。实际上,不仅线程间需要同步,进程间、信号间等等都需要同步机制。
因此, 所有 多个控制流,共同操作一个共享资源 的情况,都需要同步
3.数据混乱的原因:
1. 资源共享 ( 独享资源则不会 )
2. 调度随机 ( 意味着数据访问会出现竞争 )
3. 线程间缺乏必要的同步机制
以上 3 点中,前两点不能改变,欲提高效率,传递数据,资源必须共享。只要共享资源,就一定会出现竞争。只要存在竞争关系,数据就很容易出现混乱。
所以只能从第三点着手解决。使多个线程在访问共享资源的时候,出现互斥。
4.互斥量:
Linux 中提供一把互斥锁 mutex ( 也称之为互斥量 )
每个线程在对资源操作前都尝试先加锁,成功加锁才能操作。操作结束解锁。资源还是共享的,线程间也还是竞争的, 但通过 就将资源的访问变成互斥操作,而后与时间有关的错误也不会再产生了。

但,应注意 : 同一时刻,只能有一个线程持有该锁。
A 线程对某个全局变量加锁访问, B 在访问前尝试加锁,拿不到锁, B 阻塞。 C 线程不去加锁,而直接访问该全局变量,依然能够访问,但会出现数据混乱。
所以,互斥锁实质上是操作系统提供的一把 建议锁 ”( 又称 协同锁 ”) ,建议程序中有多线程访问共享资源的时候使用该机制。但 , 并没有强制限定。 因此,即使有了 mutex ,如果有线程不按规则来访问数据,依然会造成数据混乱。

 

5.互斥锁主要应用函数:

pthread_mutex_init 函数。
pthread_mutex_destroy 函数。
pthread_mutex_lock 函做。
pthread_mutex_trylock 函数。
pthread_mutex_unlock 函数。
以上 5 个函数的返回值都是:成功返回 0 ,失败返回错误号。
pthread_mutex_t 类型,其本质是一个结构体。 为简化理解,应用时可忽略其实现细节,简单当成
整数看待。
pthread_mutex_t mutex ;变量 mutex 只有两种取值 1 0
6.使用互斥锁的步骤:
1. pthread_mutex_t mutex : 创建锁
2. pthread_mutex_init :初始化
3. pthread_mutex_lock :加锁
4. 访问共享数据 (stdout)
5. pthread_mutex_unlock :解锁
6. pthread_mutex_destroy :销毁锁
7.加锁和解锁:
lock 尝试加锁,如果加锁不成功,线程阻塞,阻塞到持有该互斥量的其他线程解锁为止
unlock 主动解锁函数。同时将阻塞在该锁上的所有线程全部唤醒,至于哪个线程先被唤醒,取决于优先级、调度。默认 : 先阻塞、先唤醒。
例如 : T1 T2 T3 T4 使用一把 mutex 锁。 T1 加锁成功,其他线程均阻塞,直至 T1 解锁。 T1 解锁后, T2 T3T4 均被唤醒,并自动再次尝试加锁。
可假想 mutex init 成功初值为 1. lock 功能是将 mutex--. unlock 则将 mutex++
8.trylock和lock:
lock 加锁失败会阻塞,等待锁释放。
trylock 加锁失败直接返回错误号 ( : EBUSY )不阻塞
使用注意事项:
尽量保证锁的粒度,越小越好。 ( 访问共享数据前, 加锁。访问结束后,应立即解锁
互斥锁:本质是结构体,我们可以看做是整数,初值为 1 pthread_mutex_init() 函数调用成功)
加锁: -- 操作,阻塞线程。
解锁: ++ 操作,唤醒阻塞在锁上的线程
try 锁:尝试加锁,成功 -- ;失败,继续其他业务功能代码
9.死锁:
是使用锁不恰当导致的现象
1. 线程试图对同一个互斥量 A 加锁两次。(连续调用 pthread_mutex_lock 两次及以上)

2.线程1拥有A锁,请求获得B:线程2拥有B锁,请求获得A锁。

 

10.读写锁:

与互斥量类似,但读写锁允许更高的并行性。
其特性为 : 锁只有一把;写独占,读共享;写锁优先级高;
读写锁状态:
特别强调。读写锁只有一把,但其具备两种状态 :
1. 读模式下加锁状态 ( 读锁 )
2. 写模式下加锁状态 ( 写锁 )
读写锁特征:
1. 读写锁是 写模式加锁 成功时, 其他线程尝加锁都会被阻塞。
2. 读写锁是 读模式加锁 成功时,其他线程以写模式加锁会阻塞。
3. 读写锁是 读模式加锁 时,既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求。优先满足写模式锁。 读锁、写锁并行阻塞,写锁优先级高 .
读写锁也叫共享 独占锁。
a. 当读写锁以读模式锁住时,它是以共享模式锁住的,其他读线程可以读取内容
b. 当它以写模式锁住时,它是以独占模式锁住的,其他尝试操作的线程均会被阻塞
读写锁非常适合于对数据结构读的次数远大于写的情况。

读写锁主要应用函数:

pthread_rwlock_init 函数。
pthread_rwlock_destroy 函数。
pthread_rwlock_rdlock 函数。
pthread_rwlock_wrlock 函数。
pthread_rwlock_tryrdlock 函数。
pthread_rwlock_trywrlock 函数。
pthread_rwlock_unlock 函数。
以上 7 个函数的返回值都是,成功返回 0 ,失败直接返 回惜误号。 pthread_rwlock_t 类型 用于定义一个读写锁变量
pthread_rwlock_t rwlock;
初始化:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
1 :传读写锁变量
2 attr 表示读写锁属性,通常使用默认值,传 NULL 即可。
销毁:
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
1 :传读写锁变量
读方式请求读写锁:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
1 :传读写锁变量
写方式请求读写锁:
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
1 :传读写锁变量
解锁:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
1 :传读写锁变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值