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
:传读写锁变量