目录
一、STL,智能指针和线程安全
STL中的容器是否是线程安全的?
智能指针是否是线程安全的?
二、其他常见的各种锁
三、自旋锁
四、读者写者问题
读写锁接口
读者优先伪代码
一、STL,智能指针和线程安全
STL中的容器是否是线程安全的?
不是 .
原因是 , STL 的设计初衷是将性能挖掘到极致 , 而一旦涉及到加锁保证线程安全 , 会对性能造成巨大的影响 .
而且对于不同的容器 , 加锁方式的不同 , 性能可能也不同 ( 例如 hash 表的锁表和锁桶 ).
因此 STL 默认不是线程安全 . 如果需要在多线程环境下使用 , 往往需要调用者自行保证线程安全 .
智能指针是否是线程安全的?
对于 unique_ptr, 由于只是在当前代码块范围内生效 , 因此不涉及线程安全问题 .
对于 shared_ptr, 多个对象需要共用一个引用计数变量 , 所以会存在线程安全问题 . 但是标准库实现的时候考虑到了这个问题 , 基于原子操作 (CAS) 的方式保证 shared_ptr 能够高效 , 原子的操作引用计数。
静态成员需要类内声明,类外定义;但是const静态成员可以类内定义。
二、其他常见的各种锁
悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。
CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。
自旋锁,公平锁,非公平锁?
三、自旋锁

在POSIX标准中,存在互斥锁,在上锁时trylock就是非阻塞上锁,当申请锁失败时,会被直接返回。
while(1)
{
trylock;
}
这就是一个简单的自旋锁机制。
但是pthread库其实是实现了自旋锁的

机制与互斥锁一致。并且自旋锁拥有互斥的功能。
这个lock是个阻塞锁:在申请失败,内部就存在一个循环在一直申请,形态上像是阻塞。
trylock:申请失败就返回,想要自旋自己加
要不要进行自旋,取决于线程在临界区执行资源的时长,长时间自旋锁会持续占用CPU资源,导致CPU时间片的浪费。因此,自旋锁适用于那些预期锁的持有时间极短的场景,如处理器级的同步操作或多核系统中利用不同核的并行性。
四、读者写者问题
读写锁
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。
对于CP之间
但是对于读写之间:
ww:互斥竞争
wr:互斥、同步
rr:共享
读者之间与消费者之间的区别
读者只会读数据,并不会消费数据,所以读者之间是共享的
对一把读写锁,以读者的身份加锁
对一把读写锁,以写的身份加锁

解锁


注意:写独占一把锁,读共享读锁,读者优先
读写锁接口
设置读写优先
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref);
/*
pref 共有 3 种选择
PTHREAD_RWLOCK_PREFER_READER_NP ( 默认设置 ) 读者优先,可能会导致写者饥饿情况
PTHREAD_RWLOCK_PREFER_WRITER_NP 写者优先,目前有 BUG ,导致表现行为和
PTHREAD_RWLOCK_PREFER_READER_NP 一致
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 写者优先,但写者不能递归加锁
*/
初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t
*restrict attr);
销毁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
加锁和解锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
读者优先伪代码
1.写者之间一定是互斥的,但是读者共享的。
2.读的时候不允许数据写入,写的时候不允许数据读取(不同身份的角色互斥)
读者优先伪代码需要维护一个读者的个数,写者优先需要维护一个写者的个数。

设置一个全局的共享读者计数器,出现读者的时候,上读锁,读者++
一旦出现读者,就不允许写者进行写入(1.写者持有写锁,继续写入,读者阻塞 2.写者不持有写锁,读者直接占有写锁)
读取的时候,一个线程读取完成之后,读者--,读者全部读取完成之后,才会把写锁还给写者,让写者进行写入。