读写锁

Linux系统编程_课时83+84_读写锁的特性+使用场景

久未见 提交于 2019-11-29 17:16:31
课时83+84_读写锁的特性+使用场景 文章目录 课时83+84_读写锁的特性+使用场景 1、读写锁的特性 1、读写锁是几把锁 2、读写锁的类型 3、读写锁的特性 2、读写锁的使用场景 2.1、线程A加写锁成功,线程B请求读锁 2.2、线程A持有读锁,线程B请求写锁 2.3、线程A持有读锁,线程B请求读锁 2.4、线程A持有读锁,然后线程B请求写锁,然后线程C请求读锁 2.5、线程A持有写锁,然后线程B请求读锁,然后线程C请求写锁 3、互斥锁、读写锁的选择 1、读写锁的特性 1、读写锁是几把锁 读写锁只有一把锁,有读属性和写属性。 pthread_rwlock_t lock ; 2、读写锁的类型 (1)读锁:对内存做读操作 (2)写锁:对内存做写操作 3、读写锁的特性 (1)线程A加 读锁 成功,又来了三个线程,做 读 操作,可以 加锁成功 。 读共享---并行处理 (2)线程A加 写锁 成功,又来了三个线程,做 读 操作,三个线程 阻塞 。 写独占---串行处理 (3)线程A加 读锁 成功,又来了B线程加 写锁 阻塞,又来了C线程加 读锁阻塞 。 读写不能同时 写的优先级高 线程A解锁后,线程B处理,线程B解锁后,线程C处理。 2、读写锁的使用场景 2.1、线程A加写锁成功,线程B请求读锁 线程B阻塞 :读写不能同时 2.2、线程A持有读锁,线程B请求写锁 线程B阻塞

C++11 实现读写锁 read_write_mutex

£可爱£侵袭症+ 提交于 2019-11-29 09:40:58
读写锁 read_write_mutex 对于一个数据操作,简单的分可以分为读和写。 但是经常会遇到多人同时访问一个数据的情况: 多人读 多人写 有人读,有人写 处理这种情况,常用的方式是加锁( Mutex ): 读与读之间,允许并发。 读与写,写与写之间互斥。 所以读写锁需要支持以上两种情况。 读写锁 // file: read_write_mutex.h # pragma once # include <mutex> # include <condition_variable> namespace zone { class read_write_mutex { public : read_write_mutex ( ) = default ; ~ read_write_mutex ( ) = default ; read_write_mutex ( const read_write_mutex & ) = delete ; read_write_mutex & operator = ( const read_write_mutex & ) = delete ; read_write_mutex ( const read_write_mutex && ) = delete ; read_write_mutex & operator = ( const read_write

读写锁的死锁问题该如何预测?滴滴高级专家工程师这样解决

荒凉一梦 提交于 2019-11-29 06:39:43
本文作者:杜雨阳 滴滴 | 高级专家工程师-Linux内核 导读:死锁是多线程和分布式程序中常见的一种严重问题。死锁是毁灭性的,一旦发生,系统很难或者几乎不可能恢复;死锁是随机的,只有满足特定条件才会发生,而如果条件复杂,虽然发生概率很低,但是一旦发生就非常难重现和调试。使用锁而产生的死锁是死锁中的一种常见情况。Linux 内核使用 Lockdep 工具来检测和特别是预测锁的死锁场景。然而,目前 Lockdep 只支持处理互斥锁,不支持更为复杂的读写锁,尤其是递归读锁(Recursive-read lock)。因此,Lockdep 既会出现由读写锁引起的假阳性预测错误,也会出现假阴性预测错误。本工作首先解密 Lockdep工具,然后提出一种通用的锁的死锁预测算法设计和实现(互斥锁可以看做只使用读写锁中的写锁),同时证明该算法是正确和全面的解决方案。 今年初,我们相继解决了对滴滴基础平台大规模服务器集群影响严重的三个内核故障,在我们解决这些问题的时候,很多时间和精力都花在去寻找是谁在哪里构成了死锁,延误了故障排除时间,因此当时就想有没有什么通用的方法能够帮助我们对付死锁问题。但是因为时间紧迫,只能针对性地探索和处理这几个具体问题。在最终成功修复了这几个内核故障后,终于有一些时间静下来去深入思考死锁发生的原因和如何去检测和预测死锁。随着对这个问题的深入研究

Linux线程间同步的几种方式

删除回忆录丶 提交于 2019-11-29 02:43:27
信号量 信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在sem_wait的时候,就阻塞在那里)。当信号量为单值信号量时,也可以完成一个资源的互斥访问。信号量测重于访问者对资源的有序访问,在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。 有名信号量 可以用于不同进程间或多线程间的互斥与同步 创建打开有名信号量 sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); //成功返回信号量指针;失败返回SEM_FAILED,设置errno name是文件路径名,但不能写成/tmp/a.sem这样的形式,因为在linux下,sem都是在/dev/shm目录下,可写成"/mysem"或"mysem",创建出来的文件都是"/dev/shm/sem.mysem",mode设置为0666,value设置为信号量的初始值.所需信号灯等已存在条件下指定O_CREAT|O_EXCL却是个错误。 关闭信号量,进程终止时,会调用它 int sem

ZooKeeper实现读写锁

浪尽此生 提交于 2019-11-28 12:09:27
1 读写锁的概念 读写锁是计算机程序的并发控制的一种同步机制,用于解决读写问题,读操作可并发重入,写操作是互斥的。 读写锁有多种读写权限的优先级策略,可以设计为读优先、写优先或不指定优先级。 读优先:允许最大并发的读操作,但可能会饿死写操作;因为写操作必须在没有任何读操作的时候才能够执行。 写优先:只要排队队列中有写操作,读操作就必须等待; 不指定优先级:对读操作和写操作不做任何优先级的假设 不指定优先级的策略,最适合使用ZooKeeper的子节点模式来实现,今天就来尝试这种策略。 2 锁设计 同前面介绍的普通分布式锁,也使用子节点模式实现。先用容器模式(CreateMode.CONTAINER)创建唯一的锁节点,每个锁客户端在锁节点下使用临时循序模式(CreateMode. SEQUENTIAL)创建子节点。这些子节点会自动在名称后面追加10位数字。 2.1 如何标识读锁还是写锁? 有两种简单的方案:在子节点名中标识、在节点的值中标识。如果采用在值中标识,每次子节点列表后,还需要再分别读一下子节点的值,才能判断是读锁还是写锁,会比较耗时。如果在子节点名称中标识,会面临一个问题:在同一个节点中创建的子节点,如果给定的名称不同,追加的10位数字是否仍然是递归的? 写个测试用例验证一下。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

ZooKeeper实现读写锁

霸气de小男生 提交于 2019-11-28 07:35:43
在上一篇文章,我们已经实现了分布式锁。今天更进一步,在分布式锁的基础之上,实现读写锁。 完整代码在 https://github.com/SeemSilly/codestory/tree/master/research-zoo-keeper 1 读写锁的概念 参考维基百科的条目: https://zh.wikipedia.org/wiki/读写锁 读写锁是计算机程序的并发控制的一种同步机制,用于解决读写问题,读操作可并发重入,写操作是互斥的。 读写锁有多种读写权限的优先级策略,可以设计为读优先、写优先或不指定优先级。 读优先:允许最大并发的读操作,但可能会饿死写操作;因为写操作必须在没有任何读操作的时候才能够执行。 写优先:只要排队队列中有写操作,读操作就必须等待; 不指定优先级:对读操作和写操作不做任何优先级的假设 不指定优先级的策略,最适合使用ZooKeeper的子节点模式来实现,今天就来尝试这种策略。 2 锁设计 同前面介绍的普通分布式锁,也使用子节点模式实现。先用容器模式(CreateMode.CONTAINER)创建唯一的锁节点,每个锁客户端在锁节点下使用临时循序模式(CreateMode. SEQUENTIAL)创建子节点。这些子节点会自动在名称后面追加10位数字。 2.1 如何标识读锁还是写锁? 有两种简单的方案:在子节点名中标识、在节点的值中标识。如果采用在值中标识

多线程与高并发(六) Lock

只愿长相守 提交于 2019-11-28 07:13:59
之前学习了如何使用synchronized关键字来实现同步访问,Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。 不同于synchronized是Java语言的关键字,是内置特性,Lock不是Java语言内置的,Lock是一个类,通过这个类可以实现同步访问。而且synchronized同步块执行完成或者遇到异常是锁会自动释放,而lock必须调用unlock()方法释放锁,因此在finally块中释放锁。 一、 Lock 接口 先看看lock接口定义了哪些方法: void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition();

互斥锁/读写锁

女生的网名这么多〃 提交于 2019-11-28 05:54:52
原创转载请注明出处: https://www.cnblogs.com/agilestyle/p/11395812.html 互斥锁 在访问共享资源之前进行加锁操作,在访问完成之后进行解锁操作。加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前线程解锁。如果解锁时有一个以上的线程阻塞,那么所有该锁上的线程都会变成就绪状态,第一个变为就绪状态的线程又执行加锁操作,那么其他的线程又会进入等待。在这种方式下,只有一个线程能够访问被互斥锁保护的资源。举个形象的例子:多个人抢一个马桶 读写锁 读写锁既是互斥锁,又是共享锁,read模式是共享,write模式是互斥(排他锁),参考JUC包下的ReadWriteLock 读写锁的三种状态:读加锁,写加锁,不加锁 一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。只有一个线程可以占有写状态的锁,但可以有多个线程同时占有读状态的锁,这就是它可以实现高并发的原因。 当处于写状态锁时,任何想要尝试获得锁的线程都会被阻塞,直到写状态锁被释放。 当处于读状态锁时,允许其他线程获得它的读状态锁,但是不允许获得它的写状态锁,直到所有线程的读状态锁被释放。 为来避免想要尝试写操作的线程一直得不到写状态锁而处于线程饥饿,当读写锁感知到有线程想要获得写状态锁时,便会阻塞其后想要获得读状态的线程。所以读写锁非常适合多读少写的情况。 来源:

读写锁(ReentrantReadWriteLock)

ε祈祈猫儿з 提交于 2019-11-27 14:10:46
重点:   1、读锁共享   2、写锁互斥   3、读写锁互斥 锁降级 :将写锁降级为读锁。(先获取写锁,再获取读锁,再释放写锁,最后释放读锁) 造成锁降级的原因:出于性能考虑,一般情况下,都将锁定的动作,精确到具体的语句块,在两个锁的语句块之间,有可能线程的交替执行,造成线程安全问题。 解决的方法:   1、将锁的范围扩大。   2、使用锁降级。 为什么需要锁降级:  伪代码: w.lock();//写锁 writeSomeDate();//修改某些数据 w.unlock();//释放写锁 r.lock();//读锁 readSomeDate();//获取某个数据 r.unlock();//释放读锁 此时,获取数据的时候,就有线程安全问题。 修改后的代码为: w.lock();//写锁 writeSomeDate();//修改某些数据 r.lock();//读锁 w.unlock();//释放写锁 readSomeDate();//获取某个数据 r.unlock();//释放读锁 将读锁的锁定动作,放入到写锁的释放之前,就可以将锁降级为读锁。    来源: https://www.cnblogs.com/chen--biao/p/11366952.html

Qt : QThread中的互斥、读写锁、信号量、条件变量

女生的网名这么多〃 提交于 2019-11-27 05:35:53
在gemfield的《从pthread到QThread》一文中我们了解了线程的基本使用,但是有一大部分的内容当时说要放到这片文章里讨论,那就是线程的同步问题。关于这个问题,gemfield在《从进 程到线程》中有一个比喻,有必要重新放在下面温习下: 最后用一个比喻来总结下: 1、一个进程就好比一个房子里有一个人; 2、clone创建线程就相当于在这个房子里添加一个人; 3、fork创建进程就相当于再造一个房子,然后在新房子里添加一个人; 有了上面的比喻后,我们就清楚很多了: 1、线程之间有很多资源可以共享:比如厨房资源、洗手间资源、热水器资源等; 2、而对于进程来说,一个概念就是进程间通信(你要和另外一个房子里的人通信要比一个房子里的两个人之间通信复杂); 3、线程之间因为共享内存,所以通过一个全局的变量就可以交换数据了; 4、但与此同时,对于线程来说,又有新的概念产生了: a、一个人使用洗手间的时候,得锁上以防止另一个人对洗手间的访问; b、一个人(或几个人)睡觉的时候,另外一个人可以按照之前约定的方式来叫醒他; c、热水器的电源要一直开着,直到想洗澡的人数减为0; 上面的概念,在gemfield的后文中术语化的时候,你就不会再觉得很深奥或者枯燥了。 对于上面的a:一个人使用洗手间的时候,得锁上以防止另一个人对洗手间的访问。我们在QThread里使用的就是QMutext这个互斥了