欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 常见的锁与线程安全

常见的锁与线程安全

2025/7/5 13:02:40 来源:https://blog.csdn.net/2302_80190394/article/details/144538156  浏览:    关键词:常见的锁与线程安全

目录

一、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.写者不持有写锁,读者直接占有写锁)

读取的时候,一个线程读取完成之后,读者--,读者全部读取完成之后,才会把写锁还给写者,让写者进行写入。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词