互斥锁

线程同步

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

常见的缓存穿透,缓存击穿,缓存雪崩解决方案分析

随声附和 提交于 2019-11-29 08:04:17
来源: 常见的缓存穿透,缓存击穿,缓存雪崩解决方案分析 前言 设计一个缓存系统,不得不要考虑的问题就是:缓存穿透、缓存击穿与失效时的雪崩效应。 缓存穿透 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。 解决方案 有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。 缓存雪崩 缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。 解决方案 缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开

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

荒凉一梦 提交于 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

Java 并发:内置锁 Synchronized

喜夏-厌秋 提交于 2019-11-28 23:50:35
在多线程编程中,线程安全问题是一个最为关键的问题,其核心概念就在于正确性,即当多个线程访问某一共享、可变数据时,始终都不会导致数据破坏以及其他不该出现的结果。而所有的并发模式在解决这个问题时,采用的方案都是序列化访问临界资源 。在 Java 中,提供了两种方式来实现同步互斥访问:synchronized 和 Lock。本文针对 synchronized 内置锁 详细讨论了其在 Java 并发 中的应用,包括它的具体使用场景(同步方法、同步代码块、实例对象锁 和 Class 对象锁)、可重入性 和 注意事项。 一. 线程安全问题   在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个 共享、可变资源 的情况,这种资源可以是:一个变量、一个对象、一个文件等。特别注意两点, 共享: 意味着该资源可以由多个线程同时访问; 可变: 意味着该资源可以在其生命周期内被修改。  所以,当多个线程同时访问这种资源的时候,就会存在一个问题:    由于每个线程执行的过程是不可控的,所以需要采用同步机制来协同对对象可变状态的访问。 举个 数据脏读 的例子: //资源类 class PublicVar { public String username = "A"; public String password = "AA"; //同步实例方法 public

线程

人走茶凉 提交于 2019-11-28 21:54:44
线程 文章目录 线程 1 概述 1.1 线程机制分类和特性 1.2 线程标识 2 线程编程 2.1 线程基本编程 3 线程间的同步与互斥 3.1 互斥锁线程控制 3.2 信号量线程控制 4 线程属性 4.1 概述 4.2 函数 5 生产者消费者实验 5.1 概述 5.2 解决方案 5 生产者消费者实验 5.1 概述 5.2 解决方案 1 概述 线程进程内独立的一条运行路线,处理器调度的小单元,也可以称为轻量级进程。线程可以对进程的内存空间和资 源进行访问,并与同一进程中的其他线程共享。 典型进程只有一个控制线程,有多个控制线程后,进程在某一时刻能做不止一件事。 为每种事件类型分配单独的处理线程,可简化处理异步事件的代码。 多个线程可自动访问相同的存储地址空间和文件描述符。一个进程的所有信息对进程的所有线程共享。 分解问题从而提高程序吞吐量,单线程进程完成多任务需把任务串行化,而多线程中相互独立的处理可以交叉进行。 使用多线程可改善响应时间。 注 :多线程程序在单处理器上运行也能改善响应时间和吞吐量。 1.1 线程机制分类和特性 用户级线程 :用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行选择决定。如果一个进程中的某一个线程调用了一个阻塞 的系统调用函数,那么该进程包括该进程中的其他所有线程也同时被阻塞。主要缺点是无法发挥多处理器的优势。 轻量级线程

Python 进阶必备:线程模块 threading

拥有回忆 提交于 2019-11-28 19:05:54
文章目录 1. 戏说线程和进程 2. 创建并使用线程 3. 线程同步 3.1 线程锁 Lock 3.2 信号量 Semaphore 3.3 事件Event 3.4 条件 Condition 1. 戏说线程和进程 对于新手来说,首先要理解线程的概念,以及为什么需要线程编程。什么是线程呢?网上一般是这样定义的:线程(thread)是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。哈哈,你听懂了吗?我觉得这样的定义纯粹是自说自话:新手看完了一脸懵逼,老鸟看完了不以为然。咱们还是用白话解释一下吧: 假定你经营着一家物业管理公司。最初,业务量很小,事事都需要你亲力亲为,给老张家修完暖气管道,立马再去老李家换电灯泡——这叫单线程,所有的工作都得顺序执行。 后来业务拓展了,你雇佣了几个工人,这样,你的物业公司就可以同时为多户人家提供服务了——这叫多线程,你是主线程。 工人们使用的工具,是物业管理公司提供的,大家共享——这叫多线程资源共享。 工人们在工作中都需要管钳,可是管钳只有一把——这叫冲突。解决冲突的办法有很多,比如排队、等同事用完后的微信通知等——这叫线程同步。 业务不忙的时候,你就在办公室喝喝茶。下班时间一到,你群发微信,所有的工人不管手头的工作是否完成,都立马撂下工具,跟你走人。因此如果有必要,你得避免不要在工人正忙着的时候发下班的通知—

python线程互斥锁Lock(29)

自闭症网瘾萝莉.ら 提交于 2019-11-28 16:28:49
在前一篇文章 python线程创建和传参 中我们介绍了关于python线程的一些简单函数使用和线程的参数传递,使用多线程可以同时执行多个任务,提高开发效率,但是在实际开发中往往我们会碰到线程同步问题,假如有这样一个场景:对全局变量累加1000000次,为了提高效率,我们可以使用多线程完成,示例代码如下: # !usr/bin/env python # -*- coding:utf-8 _*- """ @Author:何以解忧 @Blog(个人博客地址): shuopython.com @WeChat Official Account(微信公众号):猿说python @Github:www.github.com @File:python_thread_lock.py @Time:2019/10/17 21:22 @Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累! """ # 导入线程threading模块 import threading # 声明全局变量 g_num = 0 def my_thread1(): # 声明全局变量 global g_num # 循环 1000000 次,每次累计加 1 for i in range(0,1000000): g_num = g_num + 1 def my_thread2(): # 声明全局变量

并发编程常见术语

百般思念 提交于 2019-11-28 13:54:19
原创转载请注明出处: https://www.cnblogs.com/agilestyle/p/11409772.html 并发编程领域可以抽象成三个核心问题:分工、同步、互斥。 并发:指两个或多个事件在同一时间间隔内发生 ,这些事件宏观上是同时发生的,但微观上是交替发生的。比如:某天上午先约女生A出去玩,再约女生B出去玩 并行:指两个或多个事件在同一时刻同时发生 。比如:某天上午同时约两个女生出去玩 程序:指的是一个指令序列。 进程控制块PCB:指的是系统为每个运行的程序配置的一个数据结构,用来描述进程的各种信息(如程序代码的存放位置)。 进程实体:由程序段、数据段、PCB三部分组成,是静态的。 进程:是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位,是动态的。 线程:是一个基本的CPU执行单元,也是程序执行流的最小单位。 引入线程后,进程是资源分配的基本单位,线程是调度的基本单位。 互斥:同一时刻,只允许一个线程访问共享变量。 同步:线程之前如何通信、协作 临界区:一段互斥执行的代码 可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到 原子性:一个或多个操作在CPU执行的过程中不被中断的特性。原子性的本质其实不是不可分割,不可分割只是外在表现,其本质是多个资源间有一致性的要求,操作的中间状态对外不可见。所以解决原子性的问题,是要保证中间状态对外不可见。

JDK1.6 对 synchronized 的锁优化

房东的猫 提交于 2019-11-28 12:17:02
1. 背景 在 JDK 1.6 中对锁的实现引入了大量的优化。 目的 减少锁操作的开销 。 2. 锁优化 在看下面的内容之间,希望大家对 Mark Word 有个大体的理解。Java 中一个对象在堆中的内存结构是这样的: Mark Word 是这样的: 2.1 适应性自旋锁 自旋锁的思想: 让一个线程在请求一个共享数据的锁时执行忙循环(自旋)一段时间,如果在这段时间内能获得锁,就可以 避免进入阻塞状态 。 自旋锁的缺点: 需要进行忙循环操作 占用 CPU 时间 ,它只适用于 共享数据的锁定状态很短的场景 。 若锁被其他线程长时间占用,会带来许多性能上的开销。所以自旋的次数不再固定。由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。 如果共享数据的锁定状态持续时间较短,切换线程不值得(会有上下文切换),可以利用自旋锁尝试一定的次数。 2.2 锁消除 JIT 编译时,会去除不可能存在竞争的锁。通过 JIT 的逃逸分析 来 消除一些没有在当前同步块以外被其他线程共享的数据的锁的保护 ,通过逃逸分析在 TLAB 来分配对象,这样就不存在共享数据带来的线程安全问题。 2.3 锁粗化 减少不必要的紧连在一起的 lock,unlock 操作, 将多个连续的锁扩展成一个范围更大的锁 。 2.4 偏向锁(重入锁) 为了在无线程竞争的情况下避免在锁获取过程中执行不必要的 CAS 原子指令,因为