条件变量

Java线程之Lock

一曲冷凌霜 提交于 2019-11-30 22:18:48
重入锁 Java中的重入锁(即ReentrantLock)与Java内置锁一样,是一种排它锁。使用synchronized的地方一定可以用ReentrantLock代替。 重入锁需要显示请求获取锁,并显示释放锁。为了避免获得锁后,没有释放锁,而造成其它线程无法获得锁而造成死锁,一般建议将释放锁操作放在finally块里,如下所示。 123456 try{ renentrantLock.lock(); } finally { renentrantLock.unlock();} 如果重入锁已经被其它线程持有,则当前线程的lock操作会被阻塞。除了lock()方法之外,重入锁(或者说锁接口)还提供了其它获取锁的方法以实现不同的效果。 lockInterruptibly() 该方法尝试获取锁,若获取成功立即返回;若获取不成功则阻塞等待。与lock方法不同的是,在阻塞期间,如果当前线程被 打断(interrupt) 则该方法抛出InterruptedException。该方法提供了一种解除死锁的途径。 tryLock() 该方法试图获取锁,若该锁当前可用,则该方法立即获得锁并立即返回true;若锁当前不可用,则立即返回false。该方法 不会阻塞 ,并提供给用户对于成功获利锁与获取锁失败进行不同操作的可能性。 tryLock(long time, TimeUnit unit)

Java线程之Lock

橙三吉。 提交于 2019-11-30 21:38:13
重入锁 Java中的重入锁(即ReentrantLock)与Java内置锁一样,是一种排它锁。使用synchronized的地方一定可以用ReentrantLock代替。 重入锁需要显示请求获取锁,并显示释放锁。为了避免获得锁后,没有释放锁,而造成其它线程无法获得锁而造成死锁,一般建议将释放锁操作放在finally块里,如下所示。 123456 try{ renentrantLock.lock(); } finally { renentrantLock.unlock();} 如果重入锁已经被其它线程持有,则当前线程的lock操作会被阻塞。除了lock()方法之外,重入锁(或者说锁接口)还提供了其它获取锁的方法以实现不同的效果。 lockInterruptibly() 该方法尝试获取锁,若获取成功立即返回;若获取不成功则阻塞等待。与lock方法不同的是,在阻塞期间,如果当前线程被 打断(interrupt) 则该方法抛出InterruptedException。该方法提供了一种解除死锁的途径。 tryLock() 该方法试图获取锁,若该锁当前可用,则该方法立即获得锁并立即返回true;若锁当前不可用,则立即返回false。该方法 不会阻塞 ,并提供给用户对于成功获利锁与获取锁失败进行不同操作的可能性。 tryLock(long time, TimeUnit unit)

Java中的monitor机制

孤人 提交于 2019-11-30 17:11:11
monitor概念 管程,监视器。在操作系统中,存在着semaphore和mutex,即信号量和互斥量,使用基本的mutex进行开发时,需要小心的使用mutex的down和up操作,否则容易引发死锁问题。为了更好的编写并发程序,在mutex和semaphore基础上,提出了更高层次的同步原语,实际上,monitor属于编程语言的范畴,C语言不支持monitor,而java支持monitor机制。 一个重要特点是,在同一时间,只有一个线程/进程能进入monitor所定义的临界区,这使得monitor能够实现互斥的效果。无法进入monitor的临界区的进程/线程,应该被阻塞,并且在适当的时候被唤醒。显然,monitor作为一个同步工具,也应该提供这样管理线程/进程的机制。 monitor这个机制之所以被称为:更高级的原语,它不可避免的需要对外屏蔽这些机制,并且在内部实现这些机制,使得monitor成为一个简洁易用的借口。 monitor基本元素 临界区 monitor对象和锁 条件变量以及定义在monitor对象上的wait,signal操作 使用monitor主要是为了互斥进入临界区,为了能够阻塞无法进入临界区的进程,线程,需要一个monitor object来协助,这个object内部会有相应的数据结构,例如列表,用来保存被阻塞的线程

多线程的同步与互斥(互斥锁、条件变量、读写锁、自旋锁、信号量)

天大地大妈咪最大 提交于 2019-11-30 13:23:52
多线程的同步与互斥(互斥锁、条件变量、读写锁、自旋锁、信号量) 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/daaikuaichuan/article/details/82950711 文章目录 一、同步与互斥的概念 二、互斥锁(同步) 三、条件变量(同步) 1、线程的条件变量实例1 2、线程的条件变量实例2 3、虚假唤醒(spurious wakeup) 四、读写锁(同步) 五、自旋锁(同步) 六、信号量(同步与互斥) 一、同步与互斥的概念    现代操作系统基本都是多任务操作系统,即同时有大量可调度实体在运行。在多任务操作系统中,同时运行的多个任务可能: 都需要 访问/使用同一种资源 ; 多个任务之间有依赖关系,某个任务的运行 依赖 于另一个任务。 【同步】:    是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是: 两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。 【互斥】:    是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段

生产者-消费者问题

烂漫一生 提交于 2019-11-29 16:28:12
目录 1. 概述 定义 缓冲区 2. 典型模型 模型一 模型二 可选需求 3. 数据结构队列C语言实现 4. 代码实现——互斥锁 + 条件变量 5. 代码实现——互斥锁 + Posix有名信号量 6. 代码实现——互斥锁 + Posix无名信号量 7. 效率对比 结论 奇怪的问题 1. 概述 定义 生产者消费者问题是线程同步的经典问题,也称为有界缓冲区问题,问题描述大致如下: 生产者和消费者之间共享一个有界数据缓冲区 一个或多个生产者(线程或进程)向缓冲区放置数据 一个或多个消费者(线程或进程)从缓冲区取出数据 缓冲区 生产者消费者问题中的缓冲区,包括队列缓冲区和环形缓冲区,它们都按照先进先出的顺序处理数据,我们现在只考虑队列缓冲区: 队列缓冲区通常使用普通的队列数据结构 队列内部实现可以是链表或数组 缓冲区有两个极端状态:缓冲区空,缓冲区满。链表队列和数组队列缓冲区空的含义相同,都是队列中没有一个元素的情形,但两者缓冲区满的含义不同: 数组队列在初始化时就必须指定最大容量,缓冲区满的条件很清晰 链表队列没有最大容量的概念,需要人为指定 此外,Posix消息队列也可以作为队列缓冲区,Posix当以无优先级消息的方式使用时,也是按照先进先出的顺序进行处理的。 本文只讨论第一种数据结构队列缓冲区,基于Posix消息队列缓冲区的生产者消费者问题,会在后续Posix消息队列中单独讲解。 2

线程同步

牧云@^-^@ 提交于 2019-11-29 13:48:59
目录 1. 线程同步概述 线程同步定义 线程同步方法 2. 互斥锁 互斥锁概念 互斥锁基本API 初始化与销毁 上锁与解锁 两个特殊的上锁函数 示例代码 3. 避免死锁 线程的死锁概念 产生死锁的四个必要条件 如何避免死锁 4. 条件变量 条件变量概念 条件变量基本API 初始化与销毁 等待条件满足 给线程发信号 示例代码 1. 线程同步概述 线程同步定义 线程同步,指的是 控制多线程间的相对执行顺序 ,从而在线程间 正确、有序地共享数据 ,以下为线程同步常见使用场合。 多线程执行的任务在顺序上存在依赖关系 线程间共享数据只能同时被一个线程使用 线程同步方法 在实际项目中,经常使用的线程同步方法主要分为三种: 互斥锁 条件变量 Posix信号量(包括有名信号量和无名信号量) 本节内容只介绍互斥锁和条件变量,Posix信号量后续在Posix IPC专题中介绍。 2. 互斥锁 互斥锁概念 互斥锁用于确保同一时间只有一个线程访问共享数据,使用方法为: 加锁 访问共享数据 解锁 对互斥锁加锁后,任何其他试图再次对其加锁的线程都会被阻塞,直到当前线程释放该互斥锁,解锁时所有阻塞线程都会变成可运行状态,但究竟哪个先运行,这一点是不确定的。 互斥锁基本API 初始化与销毁 互斥锁是用 pthread_mutex_t 数据类型表示的,在使用互斥锁之前,需要先进行初始化,初始化方法有两种:

(转)高效线程池之无锁化实现(Linux C)

痞子三分冷 提交于 2019-11-29 11:29:45
本文链接: https://blog.csdn.net/xhjcehust/article/details/45844901 笔者之前照着通用写法练手写过一个小的线程池版本,最近几天复习了一下,发现大多数线程池实现都离不开锁的使用,如互斥量pthread_mutex*结合条件变量pthread_cond*。众所周知,锁的使用对于程序性能影响较大,虽然现有的pthread_mutex*在锁的申请与释放方面做了较大的优化,但仔细想想,线程池的实现是可以做到无锁化的,于是有了本文。 1.常见线程池实现原理 如上图所示,工作队列由主线程和工作者线程共享,主线程将任务放进工作队列,工作者线程从工作队列中取出任务执行。共享工作队列的操作需在互斥量的保护下安全进行,主线程将任务放进工作队列时若检测到当前待执行的工作数目小于工作者线程总数,则需使用条件变量唤醒可能处于等待状态的工作者线程。当然,还有其他地方可能也会使用到互斥量和条件变量,不再赘述。 2.无锁化线程池实现原理 为解决无锁化的问题,需要避免共享资源的竞争,因此将共享工作队列加以拆分成每工作线程一个工作队列的方式。对于主线程放入工作和工作线程取出任务的竞争问题,可以采取环形队列的方式避免。在解决了锁机制之后,就只剩下条件变量的问题了,条件变量本身即解决条件满足时的线程通信问题,而信号作为一种通信方式,可以代替之,其大体编程范式为:

面试题——AQS

你说的曾经没有我的故事 提交于 2019-11-29 06:16:54
AQS 抽象同步队列简称AQS,它是一个先进先出的双向队列。AQS内部有一个CLH队列,用来记录所有等待锁的线程。AQS还拥有一个内部类ConditionObject,它是条件变量,每个条件变量的内部都维护了一个条件队列,当一个线程调用条件变量的await方法时,该线程会释放它持有的锁,并被转换为Node节点插入到条件变量对应的条件队列里,同时还会唤醒CLH队列里的一个线程获取到被释放的锁。而signal系列的方法会将condition条件队列中的节点插入到CLH队列里,等待时机获取锁。 AQS的应用 AQS支持独占锁,比如ReentranLock。还支持共享锁,比如CountDownLatch、Semaphore。在AQS中维持了一个单一的状态信息state,对于ReentranLock,state表示当前线程获取锁的可重入次数;对于CountDownLatch,state表示当前计数器的值;对于Semaphore,state表示当前可用信号的个数。 来源: https://blog.csdn.net/dl674756321/article/details/100536639

linux 条件变量

为君一笑 提交于 2019-11-29 04:22:53
在多线程编程中仅使用互斥锁来完成互斥是不够用的, 如以下情形: 假设有两个线程 t1 和 t2 , 需要这个两个线程循环对一个共享变量 sum 进行自增操作,那么 t1 和 t2 只需要使用互斥量即可保证操作正确完成,线程执行代码如所示: pthread_mutex_t sumlock= PTHREAD_MUTEX_INITIALIZER; void * t1t2(void) {   pthread_mutex_lock(&sumlock);   sum++;   pthread_mutex_unlock(&sumlock); } 如果这时需要增加另一个线程 t3 ,需要 t3 在 count 大于 100 时将 count 值重新置 0 值,那么可以 t3 可以实现如下: void * t3 (void) {   pthread_mutex_lock(&sumlock);   if (sum >= 100) {     sum = 0;     pthread_mutex_unlock(&sumlock);   } else {     pthread_mutex_unlock(&sumlock);     usleep(100);   } } 以上代码存在以下问题: 1) sum 在大多数情况下不会到达 100 , 那么对 t3 的代码来说 , 大多数情况下, 走的是 else

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