嵌入式Linux应用开发-驱动大全-同步与互斥④
嵌入式Linux应用开发-驱动大全-同步与互斥④
- 第一章 同步与互斥④
- 1.5 自旋锁spinlock的实现
- 1.5.1 自旋锁的内核结构体
- 1.5.2 spinlock在UP系统中的实现
- 1.5.3 spinlock在SMP系统中的实现
- 1.6 信号量semaphore的实现
- 1.6.1 semaphore的内核结构体
- 1.6.2 down函数的实现
- 1.6.3 up函数的实现
- 1.7 互斥量mutex的实现
- 1.7.1 mutex的内核结构体
- 1.7.2 mutex_lock函数的实现
- 1.7.2.1 fastpath
- 1.7.2.2 slowpath
- 1.7.3 mutex_unlock函数的实现
- 1.7.3.1 fastpath
- 1.7.3.2 slowpath
第一章 同步与互斥④
1.5 自旋锁spinlock的实现
自旋锁,顾名思义:自己在原地打转,等待资源可用,一旦可用就上锁霸占它。
问题来了,假设别人已经上锁了,你原地打转会占住 CPU资源了,别的程序怎么运行?它没有 CPU怎么解锁?
这个问题,有 2个答案:
① 原地打转的是 CPU x,以后 CPU y会解锁:这涉及多个 CPU,适用于 SMP系统;
② 对于单 CPU系统,自旋锁的“自旋”功能就去掉了:只剩下禁止抢占、禁止中断
我先禁止别的线程来打断我(preempt_disable),我慢慢享用临界资源,用完再使能系统抢占(preempt_enable),这样别人就可以来抢资源了。
注意:SMP就是 Symmetric Multi-Processors,对称多处理器;UP即 Uni-Processor,系统只有一个单核 CPU。
要理解 spinlock,要通过 2个情景来分析:
① 一开始,怎么争抢资源?不能 2个程序都抢到。 这挺好解决,使用原子变量就可以实现。
② 某个程序已经获得资源,怎么防止别人来同时使用这个资源。
这是使用 spinlock时要注意的地方,对应会有不同的衍生函数(_bh/_irq/_irqsave/_restore)。
1.5.1 自旋锁的内核结构体
spinlock对应的结构体如下定义,不同的架构可能有不同的实现:
上述__raw_tickets结构体中有 owner、next两个成员,这是在 SMP系统中实现 spinlock的关键。
1.5.2 spinlock在UP系统中的实现
对于“自旋锁”,它的本意是:如果还没获得锁,我就原地打转等待。等待谁释放锁? ① 其他 CPU
② 其他进程/线程
对于单 CPU系统,没有“其他 CPU”;如果内核不支持 preempt,当前在内核态执行的线程也不可能被其他线程抢占,也就“没有其他进程/线程”。所以,对于不支持 preempt的单 CPU系统,spin_lock是空函数,不需要做其他事情。
如果单 CPU系统的内核支持 preempt,即当前线程正在执行内核态函数时,它是有可能被别的线程抢占的。这时 spin_lock的实现就是调用“preempt_disable()”:你想抢我,我干脆禁止你运行。
在 UP系统中,spin_lock函数定义如下:
从以上代码可知,在 UP系统中 spin_lock()就退化为 preempt_disable(),如果用的内核不支持 preempt,那么 spin_lock()什么事都不用做。
对于 spin_lock_irq(),在 UP系统中就退化为 local_irq_disable()和 preempt_disable(),如下图所示:
假设程序 A要访问临界资源,可能会有中断也来访问临界资源,可能会有程序 B也来访问临界资源,那么使用 spin_lock_irq()来保护临界资源:先禁止中断防止中断来抢,再禁止 preempt防止其他进程来抢。
对于 spin_lock_bh(),在 UP系统中就退化为禁止软件中断和 preempt_disable(),如下图所示:
对于 spin_lock_irqsave,它跟 spin_lock_irq类似,只不过它是先保存中断状态再禁止中断,如下:
对应的 spin_unlock函数就不再讲解。
1.5.3 spinlock在SMP系统中的实现
要让多 CPU中只能有一个获得临界资源,使用原子变量就可以实现。但是还要保证公平,先到先得。比如有 CPU0、CPU1、CPU2都调用 spin_lock想获得临界资源,谁先申请谁先获得。
要想理解 SMP系统中 spinlock的实现,得举一个例子。感谢这篇文章:
Linux内核同步机制之(四):spin lock
http://www.wowotech.net/kernel_synchronization/spinlock.html
wowotech真是一个神奇的网站,里面 Linux文章的作者统一标为“linuxer”,牛!
我借用这篇文章的例子讲解,餐厅里只有一个座位,去吃饭的人都得先取号、等叫号。注意,有 2个动作:顾客从取号机取号,电子叫号牌叫号。
① 一开始取号机待取号码为 0
② 顾客 A从取号机得到号码 0,电子叫号牌显示 0,顾客 A上座;
取号机显示下一个待取号码为 1。
③ 顾客 B从取号机得到号码 1,电子叫号牌还显示为 0,顾客 B等待;
取号机显示下一个待取号码为 2。
④ 顾客 C从取号机得到号码 2,电子叫号牌还显示为 0,顾客 C等待;
取号机显示下一个待取号码为 3。
⑤ 顾客 A吃完离座,电子叫号牌显示为 1,顾客 B的号码等于 1,他上座;
⑥ 顾客 B吃完离座,电子叫号牌显示为 2,顾客 C的号码等于 2,他上座;
在这个例子中有 2个号码:取号机显示的“下一个号码”,顾客取号后它会自动加 1;电子叫号牌显示
“当前号码”,顾客离座后它会自动加 1。某个客户手上拿到的号码等于电子叫号牌的号码时,该客户上座。 在这个过程中,即使顾客 B、C同时到店,只要保证他们从取号机上得到的号码不同,他们就不会打架。
所以,关键点在于:取号机的号码发放,必须互斥,保证客户的号码互不相同。而电子叫号牌上号码的变动不需要保护,只有顾客离开后它才会变化,没人争抢它。
在 ARMv6及以上的 ARM架构中,支持 SMP系统。它的 spinlock结构体定义如下:
owner就相当于电子叫号牌,现在谁在吃饭。next就当于于取号机,下一个号码是什么。每一个 CPU从取号机上取到的号码保存在 spin_lock函数中的局部变量里。
spin_lock函数调用关系如下,核心是 arch_spin_lock:
arch_spin_lock代码如下:
图中的注释把原理讲得非常清楚了,即使不同的个体去同时取号,也可以保证取到的号码各不相同。
假设第 1个程序取到了号码,它访问了临界资源后,调用 spin_unlock,代码如下:
假如有其他程序正在 spin_lock函数中循环等待,它就会立刻判断自己手上的 next是否等于lock->tickets.owner,如果相等就表示输到它获得了锁。
深入分析_linux_spinlock_实现机制
https://blog.csdn.net/electrombile/article/details/51289813
深入分析 Linux自旋锁
http://blog.chinaunix.net/uid-20543672-id-3252604.html
Linux内核同步机制之(四):spin lock
http://www.wowotech.net/kernel_synchronization/spinlock.html
1.6 信号量semaphore的实现
1.6.1 semaphore的内核结构体
注意:这是信号量,不是信号。在前面学习异步通知时,驱动程序给应用程序发信号。现在我们讲的信号量是一种同步、互斥机制。
信号量的定义及操作函数都在 Linux内核文件 include\linux\semaphore.h中定义,如下:
初始化 semaphore之后,就可以使用 down函数或其他衍生版本来获取信号量,使用 up函数释放信号量。我们只分析 down、up函数的实现。
1.6.2 down函数的实现
如果 semaphore中的 count大于 0,那么 down函数就可以获得信号量;否则就休眠。在读取、修改 count时,要使用 spinlock来实现互斥。
休眠时,要把当前进程放在 semaphore的 wait_list链表中,别的进程释放信号量时去 wait_list中把进程取出、唤醒。
代码如下:
1.6.3 up函数的实现
如果有其他进程在等待信号量,则 count值无需调整,直接取出第 1个等待信号量的进程,把信号量给它,共把它唤醒。
如果没有其他进程在等待信号量,则调整 count。
整个过程需要使用 spinlock来保护,代码如下:
1.7 互斥量mutex的实现
1.7.1 mutex的内核结构体
mutex的定义及操作函数都在 Linux内核文件 include\linux\mutex.h中定义,如下:
初始化 mutex之后,就可以使用 mutex_lock函数或其他衍生版本来获取信号量,使用 mutex_unlock函数释放信号量。我们只分析 mutex_lock、mutex_unlock函数的实现。
这里要堪误一下:前面的视频里我们说 mutex中的 owner是用来记录获得 mutex的进程,以后必须由它来释放 mutex。这是错的!
从上面的代码可知,owner并不一定存在!
owner有 2个用途:debug(CONFIG_DEBUG_MUTEXES)或 spin_on_owner(CONFIG_MUTEX_SPIN_ON_OWNER)。 什么叫 spin on owner?
我们使用mutex的目的一般是用来保护一小段代码,这段代码运行的时间很快。这意味着一个获得mutex的进程,可能很快就会释放掉 mutex。
针对这点可以进行优化,特别是当前获得 mutex的进程是在别的 CPU上运行、并且“我”是唯一等待这个 mutex的进程。在这种情况下,那“我”就原地 spin等待吧:懒得去休眠了,休眠又唤醒就太慢了。
所以,mutex是做了特殊的优化,比 semaphore效率更高。但是在代码上,并没有要求“谁获得 mutex,就必须由谁释放 mutex”,只是在使用惯例上是“谁获得 mutex,就必须由谁释放 mutex”。
1.7.2 mutex_lock函数的实现
1.7.2.1 fastpath
mutex的设计非常精巧,比 semaphore复杂,但是更高效。
首先要知道 mutex的操作函数中有 fastpath、slowpath两条路径(快速、慢速):如果 fastpath成功,就不必使用 slowpath。
怎么理解?
这需要把 metex中的 count值再扩展一下,之前说它只有 1、0两个取值,1表示 unlocked,0表示locked,还有一类值“负数”表示“locked,并且可能有其他程序在等待”。
代码如下:
先看看 fastpath的函数:__mutex_fastpath_lock,这个函数在下面 2个文件中都有定义:
include/asm-generic/mutex-xchg.h
include/asm-generic/mutex-dec.h
使用哪一个文件呢?看看 arch/arm/include/asm/mutex.h,内容如下:
#if __LINUX_ARM_ARCH__ < 6
#include <asm-generic/mutex-xchg.h>
#else
#include <asm-generic/mutex-dec.h>
#endif
所以,对于 ARMv6以下的架构,使用 include/asm-generic/mutex-xchg.h中的__mutex_fastpath_lock函数;对于 ARMv6及以上的架构,使用 include/asm-generic/mutex-dec.h中的__mutex_fastpath_lock函数。这 2个文件中的__mutex_fastpath_lock函数是类似的,mutex-dec.h中的代码如下:
大部分情况下,mutex当前值都是 1,所以通过 fastpath函数可以非常快速地获得 mutex。
1.7.2.2 slowpath
如果 mutex当前值是 0或负数,则需要调用__mutex_lock_slowpath慢慢处理:可能会休眠等待。
__mutex_lock_common函数也是在内核文件 kernel/locking/mutex.c中实现的,下面分段讲解。
① 分析第一段代码:
② 分析第二段代码:
③ 分析第三段代码:
这个 wait_list是 FIFO(Firt In Firs Out),谁先排队,谁就可以先得到 mutex。
④ 分析第四段代码:for循环,这是重点
⑤ 分析第五段代码:收尾工作
1.7.3 mutex_unlock函数的实现
mutex_unlock函数中也有 fastpath、slowpath两条路径(快速、慢速):如果 fastpath成功,就不必使用 slowpath。
代码如下:
1.7.3.1 fastpath
先看看 fastpath的函数:__mutex_fastpath_lock,这个函数在下面 2个文件中都有定义:
include/asm-generic/mutex-xchg.h
include/asm-generic/mutex-dec.h
使用哪一个文件呢?看看 arch/arm/include/asm/mutex.h,内容如下:
#if __LINUX_ARM_ARCH__ < 6
#include <asm-generic/mutex-xchg.h>
#else
#include <asm-generic/mutex-dec.h>
#endif
所以,对于 ARMv6以下的架构,使用 include/asm-generic/mutex-xchg.h中的__mutex_fastpath_lock函数;对于 ARMv6及以上的架构,使用 include/asm-generic/mutex-dec.h中的__mutex_fastpath_lock函数。这 2个文件中的__mutex_fastpath_lock函数是类似的,mutex-dec.h中的代码如下:
大部分情况下,加 1后 mutex的值都是 1,表示无人等待 mutex,所以通过 fastpath函数直接增加 mutex的 count值为 1就可以了。
如果 mutex的值加 1后还
是小于等于 0,就表示有人在等待 mutex,需要去 wait_list把它取出唤醒,这需要用到 slowpath的函数:__mutex_unlock_slowpath。
1.7.3.2 slowpath
如果 mutex当前值是 0或负数,则需要调用__mutex_unlock_slowpath慢慢处理:需要唤醒其他进程。
__mutex_unlock_common_slowpath函数代码如下,主要工作就是从 wait_list中取出并唤醒第 1个进程:
相关文章:
嵌入式Linux应用开发-驱动大全-同步与互斥④
嵌入式Linux应用开发-驱动大全-同步与互斥④ 第一章 同步与互斥④1.5 自旋锁spinlock的实现1.5.1 自旋锁的内核结构体1.5.2 spinlock在UP系统中的实现1.5.3 spinlock在SMP系统中的实现 1.6 信号量semaphore的实现1.6.1 semaphore的内核结构体1.6.2 down函数的实现1.6.3 up函数的…...
2023年【高压电工】证考试及高压电工复审模拟考试
题库来源:安全生产模拟考试一点通公众号小程序 高压电工证考试根据新高压电工考试大纲要求,安全生产模拟考试一点通将高压电工模拟考试试题进行汇编,组成一套高压电工全真模拟考试试题,学员可通过高压电工复审模拟考试全真模拟&a…...
C/C++学习 -- 分组密算法(3DES算法)
1. 3DES算法概述 3DES(Triple Data Encryption Standard),又称为TDEA(Triple Data Encryption Algorithm),是一种对称加密算法,是DES(Data Encryption Standard)的加强版…...
C/C++面试题总结
1.new与malloc的区别 new操作符从自由存储区上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。 使用new操作符申请内存分配时无须指定内存块的大小,而malloc则需要显式地指出所需内存的尺寸。 int *p new int; delete p;//一定要配对使用n…...
Java下正面解除警告Unchecked cast: ‘java.lang.Object‘ to ‘java.util.ArrayList‘
就是我在反序列化时,遇到这样一个警告: Unchecked cast: java.lang.Object to java.util.ArrayList<com.work1.Student>然后我去网上查,有些人说用SuppressWarnings(“unchecked”)去忽略警告,但是我觉得作为一名合格的程序…...
图像处理与计算机视觉--第四章-图像滤波与增强-第二部分
目录 1.图像噪声化处理与卷积平滑 2.图像傅里叶快速变换处理 3.图像腐蚀和膨胀处理 4 图像灰度调整处理 5.图像抖动处理算法 学习计算机视觉方向的几条经验: 1.学习计算机视觉一定不能操之过急,不然往往事倍功半! 2.静下心来,理解每一个…...
[前端基础]typescript安装以及类型拓展
(0)写在前面: 作者之前都是在写js,所以这里介绍ts肯定是不能从头开始介绍了,主要在js的基础上介绍ts关于类型的几个特性,以及ts的安装还有配置问题 (1)ts和js是什么关系 通俗点来…...
网络参考资料汇总(1)
将这段时间参考的各路大佬的资料加以汇总分类: (1)FFmpeg: 基于FFmpeg进行rtsp推流及拉流(详细教程) Linux 编译安装 FFmpeg 步骤(带ffplay) Jetson 环境安装(三):jetson nano配置ffmpeg和ngin…...
Remove和RemoveLast用法
LeetCode 46 全排列 先贴代码 class Solution {List<List<Integer>> result new ArrayList<>();List<Integer> temp new ArrayList<>();public List<List<Integer>> permute(int[] nums) {dfs(nums, 0);return result;}public v…...
(一) 使用 Hugo 搭建个人博客保姆级教程(上篇)
手把手教你如何从0开始构建一个静态网站,这不需要有太多的编程和开发经验和时间投入,也基本不需要多少成本(除了个性化域名),使用GitHub和Hugo模板即可快速构建和上线一个网站。 目标读者 本文档适用于以下用户&…...
数据结构之栈
栈的模拟实现 1.栈的概念2.栈的方法3.栈的模拟实现(代码)3.1 接口My_Stack3.2 StackList3.3 异常类StackException3.4 测试类Test 1.栈的概念 2.栈的方法 3.栈的模拟实现(代码) 3.1 接口My_Stack 3.2 StackList 3.3 异常类StackException 3.4 测试类Test...
wireshark of tshark tools v3.4.0版本 支持json
tshark(1) Install tshark (Wireshark) Ver.3.4.0 on CentOS7 --It must be "ps", "text", "pdml", "psml" or "fields". TCP 协议中的三次握手和四次挥手是 TCP 连接建立和关闭的过程。 三次握手 客户端向服务器发送 SYN…...
Python开源项目月排行 2023年9月
#2023年9月2023年9月9日1fishdraw这个项目是用来随机生成一条鱼的,这条鱼特别的稀奇古怪,这个项目不依赖任何库,支持 svg, json, csv 等格式。2vizro一个用于创建模块化数据可视化应用程序的工具包。在几分钟内快速自助组装定制仪表板 - 无需…...
uniapp项目实践总结(二十五)苹果 ios 平台 APP 打包教程
导语:当你的应用程序开发完成后,在上架 ios 应用商店之前,需要进行打包操作,下面就简单介绍一下打包方法。 目录 准备工作注册账号生成证书打包配置准备工作 在打包之前,请保证你的 uniapp 应用程序编译到 ios 模拟器或者是真机调试基座环境下是可以正常运行的,苹果打包…...
MySQL查询(基础到高级)
一、单表查询: 1.基本查询: 1.1 查询多个字段: 1.查询所有字段: select * from 表名;2.查询指定字段: select 字段1,字段2 from 表名; 1.2 去除重复记录 select distinct "字段" FROM "表名"; …...
电脑通过串口助手和51单片机串口通讯
今天有时间把电脑和51单片机之间的串口通讯搞定了,电脑发送的串口数据,单片机能够正常接收并显示到oled屏幕上,特此记录一下,防止后面自己忘记了怎么搞得了。 先来两个图片看看结果吧! 下面是串口3.c的文件全部内容&a…...
【Linux】线程详解完结篇——信号量 + 线程池 + 单例模式 + 读写锁
线程详解第四篇 前言正式开始信号量引例信号量的本质信号量相关的四个核心接口生产消费者模型用环形队列实现生产者消费者模型基于环形队列的生产消费模型的原理代码演示单生产者单消费者多生产者多消费者 计数器的意义 线程池基本概念代码 单例模式STL,智能指针和线程安全STL中…...
弧度、圆弧上的点、圆的半径(r)、弧长(s)之间的关系
要计算弧度和圆弧上的点,需要知道以下几个要素: 圆的半径(r):即圆的中心到圆周上任意一点的距离。 弧长(s):从圆周上的一个点到另一个点所经过的弧长。 弧度(θ&#x…...
[AOSP] [JNI] [Android] AOSP中使用JNI
一. 简要 🍎 JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。J…...
GEE案例——如何使用长时序影像实现多波段图像加载(不同层土壤湿度)
简介: 在GEE中实现时序图像的加载主要的目的是查看影像波段或者指数的变化,这里我们使用的主要是加载常规的4个波段,然后添加一个复合波段,复合波段主要的是求4个波段的平均值,然后再次加入到原有的4个波段的时序图中。这里面主要的技术难点一个是图表的设定,另外一个就…...
Cloudflare进阶技巧:缓存利用最大化
1. 引言 cloudflare我想你应该知道是什么,一家真正意义上免费无限量的CDN,至今未曾有哥们喷它的。当然,在国内的速度确实比较一般,不过这也不能怪它。 CDN最大的特色,我想就是它的缓存功能,达到防攻击&am…...
想要精通算法和SQL的成长之路 - 二叉树的判断问题(子树判断 | 对称性 | 一致性判断)
想要精通算法和SQL的成长之路 - 二叉树的判断问题 前言一. 相同的树二. 对称二叉树三. 判断子树 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 相同的树 原题链接 这题目典型的递归题: 如果两个节点都是null,我们返回true。如果两个节点一个nul…...
(零)如何做机器视觉项目
文章目录 1 项目的前期准备1.1 从5个方面初步分析客户需求1.2 方案评估与验证1.3 签订合同 2 项目规划2.1 定义客户端的详细需求2.2 制定项目管理计划2.3 方案评审 3 详细设计3.1 硬件设备的选择与环境搭建3.2 软件开发平台与开发工具的选择3.3 机器视觉系统的整体框架与开发流…...
【Leetcode】滑动窗口合集
这里写目录标题 209.长度最小的子数组题目思路代码 3. 无重复字符的最长子串(medium)题目思路 11. 最大连续 1 的个数 III题目思路 1658. 将 x 减到 0 的最⼩操作数题目思路代码 904. 水果成篮题目思路代码 438.找到字符串中所有字母的异位词题目思路代码…...
【C++】STL详解(九)—— set、map、multiset、multimap的介绍及使用
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C学习 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:【C】STL…...
计组—— I/O系统
📕:参考王道课件 目录 一、I/O系统的基本概念 1.什么是“I/O”? 编辑2.主机如何和I/O设备进行交互? 3.I/O控制方式 (1)程序查询方式 (2)程序中断方式 (3&#x…...
基于vc6+sdk51开发简易文字识别转语音的程序
系统:window7 软件:vc6.0 目的:简易文字转语音真人发声 利用2023国庆小长假,研究如何将文言转语音,之前在网上查询相关知识,大致了解微信语音转换,翻译官之类软件的原理,但要加入神…...
DevOps:自动化部署和持续集成/持续交付(CI/CD)
DevOps:自动化部署和持续集成/持续交付(CI/CD) 在现代软件开发领域,DevOps(Development和Operations的组合)已经成为一个不可或缺的概念。它代表了一种将软件开发和运维(Operations)…...
专业图标制作软件 Image2icon 最新中文 for mac
Image2Icon是一款用于Mac操作系统的图标转换工具。它允许用户将常见的图像文件(如PNG、JPEG、GIF等)转换为图标文件(.ico格式),以便在Mac上用作应用程序、文件夹或驱动器的自定义图标。 以下是Image2Icon的一些主要功…...
数据结构:顺序表
SeqList.h #pragma once #include<stdio.h> #include<assert.h> #include<stdlib.h>typedef int SLDataType; //#define NULL 0typedef struct SeqList {SLDataType* a;int size;//顺序表中存储的有效元素的个数int capacity;//空间的大小 }SL;void SLInit(…...
网站建设 开办费/上海公司排名
本人应用PHP开发程序也小有年头了,对于PHP程序也有一些自己的简介,接触了一些国内外优秀的MVC框架,近日,突然想了解一下基本的MVC框架式如何实现的,所以开始着手研究自己动手打造出一个简单的MVC框架。对于研究的心得拿…...
网站建设一般用什么软件/搜索优化推广公司
<?php /* * author zechen * 2011-4-4 下午04:14:49 * */ //一个普遍通用的PHP连接MYSQL数据库类 class mysql { private $db_host; //数据库主机 private $db_user; //数据库用户名 private $db_pwd; //数据库用户名密码 private $db_database; //数…...
wordpress微信分享缩微图/seo网站排名厂商定制
1.前言: 在对物联网网关进行压测的时候,发现在腾讯云部署网关程序,设备接入数量只能达到4000多个长连接,之后就再也无法接入终端了。 之前在阿里云部署的时候明明可以到达2万左右,而且腾讯云的这个服务器比阿里云的硬…...
可以制作app的软件/零基础学seo要多久
在Python中,安装第三方模块,是通过包管理工具pip完成的。如果你正在使用Mac或Linux,安装pip本身这个步骤就可以跳过了。如果你正在使用Windows,请参考安装Python一节的内容,确保安装时勾选了pip和Add python.exe to Pa…...
佛山做网站建设公司/职业技能培训学校
昨晚与闺中密友聚餐,话题自然少不了女人世界的种种。不知怎么,话题就扯到了女人的头发上。从头发谈到染发又谈到染发剂,又从染发剂谈到经常染发有致癌的可能。一位朋友刚换了一种染发剂的颜色,浅棕色里掺杂着丝丝灰白,…...
中国做的比较好的网站/seo站长博客
Semaphore简介Semaphore是并发包中提供的用于控制某资源同时被访问的个数操作系统的信号量是个很重要的概念,在进程控制方面都有应用。Java 并发库 的Semaphore 可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,通过 …...