扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
锁的原理是什么?
创新互联公司于2013年开始,是专业互联网技术服务公司,拥有项目成都网站制作、网站设计网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元石台做网站,已为上家服务,为石台各地企业和个人服务,联系电话:13518219792
2008-03-28 13:00:42
一,普通锁不是有一个铜心么?拆开后可以看见上面一面是槽---钥匙背的方向,另1面是一排小孔,小孔里是长短不一的铜柱和弹簧(铜柱在靠近钥匙一面)外面用铝封口。平时铜柱因为不受力而弹出半截,而阻挡了大铜心的转动。当用对应的钥匙插入时,铜柱和钥匙上的齿接触,形成一个有规律的曲线,而闪开了大铜心上的豁口,使之能够转动。而转动使锁打开的原理就比较简单了。
二,在安全技术防范领域,具有防盗报警功能的电子密码锁代替传统的机械式密码锁,克服了机械式密码锁密码量少、安全性能差的缺点,使密码锁无论在技术上还是在性能上都大大提高一步。随着大规模集成电路技术的发展,特别是单片机的问世,出现了带微处理器的智能密码锁,它除具有电子密码锁的功能外,还引入了智能化管理、专家分析系统等功能,从而使密码锁具有很高的安全性、可靠性,应用日益广泛。本文介绍以51系列单片机为核心的智能密码锁,详细阐述了其工作原理、基本功能框图、关键设计技术及软件工作流程。
1基本原理及硬件组成
智能密码锁的系统由智能监控器和电子锁具组成。二者异地放置,智能监控器供给电子锁具所需的电源并接收其发送的报警信息和状态信息。这里采用了线路复用技术,使电能供给和信息传输共用一根二芯电缆,提高了系统的可靠性、安全性。
1.1智能监控器的基本原理及组成框图
智能监控器的组成框图,它由单片机、时钟、键盘、LCD显示器、存贮器、解调器、线路复用及监测、A/D转换、蜂鸣器等单元组成。主要完成与电子锁具之间的通信、智能化分析及通信线路的安全监测等功能。
智能监控器始终处于接收状态,以固定的格式接收电子锁具发来的报警信息和状态信息。对于报警信息,则马上通过LCD显示器及蜂鸣器发出声、光报警;对于状态信息,则存入内存,并与电子锁具在此时刻以前的历史状态进行比较,得出变化趋势,预测未来的状态变化,通过LCD显示器向值班人员提供相应信息,以供决策使用。智能监控器与电子锁具建立通信联系的同时,通过A/D转换器实时地监视流过通信线路的供电电流的变化,有效地防止人为因素造成的破坏,保证了通信线路的畅通。
1.2电子锁具基本原理及组成框图
电子锁具的组成框图,它也是以51系列单片机(AT89051)为核心,配以相应硬件电路,完成密码的设置、存贮、识别和显示、驱动电磁执行器并检测其驱动电流值、接收传感器送来的报警信号、发送数据等功能。
单片机接收键入的代码,并与存贮在EEPROM中的密码进行比较,如果密码正确,则驱动电磁执行器开锁;如果密码不正确,则允许操作人员重新输入密码,最多可输入三次;如果三次都不正确,则单片机通过通信线路向智能监控器报警。单片机将每次开锁操作和此时电磁执行器的驱动电流值作为状态信息发送给智能监控器,同时将接收来自传感器接口的报警信息也发送给智能监控器,作为智能化分析的依据。
2关键技术
为了提高智能密码锁的安全性、可靠性,本文除在器件选择上采取措施(如采用低功耗、宽温度范围的器件)外,在设计中还采用了一些关键技术。
编写过C语言程序的肯定知道通过malloc()方法动态申请内存,其中内存分配器使用的是glibc提供的ptmalloc2。 除了glibc,业界比较出名的内存分配器有Google的tcmalloc和Facebook的jemalloc。二者在避免内存碎片和性能上均比glic有比较大的优势,在多线程环境中效果更明显。
Golang中也实现了内存分配器,原理与tcmalloc类似,简单的说就是维护一块大的全局内存,每个线程(Golang中为P)维护一块小的私有内存,私有内存不足再从全局申请。另外,内存分配与GC(垃圾回收)关系密切,所以了解GC前有必要了解内存分配的原理。
为了方便自主管理内存,做法便是先向系统申请一块内存,然后将内存切割成小块,通过一定的内存分配算法管理内存。 以64位系统为例,Golang程序启动时会向系统申请的内存如下图所示:
预申请的内存划分为spans、bitmap、arena三部分。其中arena即为所谓的堆区,应用中需要的内存从这里分配。其中spans和bitmap是为了管理arena区而存在的。
arena的大小为512G,为了方便管理把arena区域划分成一个个的page,每个page为8KB,一共有512GB/8KB个页;
spans区域存放span的指针,每个指针对应一个page,所以span区域的大小为(512GB/8KB)乘以指针大小8byte = 512M
bitmap区域大小也是通过arena计算出来,不过主要用于GC。
span是用于管理arena页的关键数据结构,每个span中包含1个或多个连续页,为了满足小对象分配,span中的一页会划分更小的粒度,而对于大对象比如超过页大小,则通过多页实现。
根据对象大小,划分了一系列class,每个class都代表一个固定大小的对象,以及每个span的大小。如下表所示:
上表中每列含义如下:
class: class ID,每个span结构中都有一个class ID, 表示该span可处理的对象类型
bytes/obj:该class代表对象的字节数
bytes/span:每个span占用堆的字节数,也即页数乘以页大小
objects: 每个span可分配的对象个数,也即(bytes/spans)/(bytes/obj)waste
bytes: 每个span产生的内存碎片,也即(bytes/spans)%(bytes/obj)上表可见最大的对象是32K大小,超过32K大小的由特殊的class表示,该class ID为0,每个class只包含一个对象。
span是内存管理的基本单位,每个span用于管理特定的class对象, 跟据对象大小,span将一个或多个页拆分成多个块进行管理。src/runtime/mheap.go:mspan定义了其数据结构:
以class 10为例,span和管理的内存如下图所示:
spanclass为10,参照class表可得出npages=1,nelems=56,elemsize为144。其中startAddr是在span初始化时就指定了某个页的地址。allocBits指向一个位图,每位代表一个块是否被分配,本例中有两个块已经被分配,其allocCount也为2。next和prev用于将多个span链接起来,这有利于管理多个span,接下来会进行说明。
有了管理内存的基本单位span,还要有个数据结构来管理span,这个数据结构叫mcentral,各线程需要内存时从mcentral管理的span中申请内存,为了避免多线程申请内存时不断的加锁,Golang为每个线程分配了span的缓存,这个缓存即是cache。src/runtime/mcache.go:mcache定义了cache的数据结构
alloc为mspan的指针数组,数组大小为class总数的2倍。数组中每个元素代表了一种class类型的span列表,每种class类型都有两组span列表,第一组列表中所表示的对象中包含了指针,第二组列表中所表示的对象不含有指针,这么做是为了提高GC扫描性能,对于不包含指针的span列表,没必要去扫描。根据对象是否包含指针,将对象分为noscan和scan两类,其中noscan代表没有指针,而scan则代表有指针,需要GC进行扫描。mcache和span的对应关系如下图所示:
mchache在初始化时是没有任何span的,在使用过程中会动态的从central中获取并缓存下来,跟据使用情况,每种class的span个数也不相同。上图所示,class 0的span数比class1的要多,说明本线程中分配的小对象要多一些。
cache作为线程的私有资源为单个线程服务,而central则是全局资源,为多个线程服务,当某个线程内存不足时会向central申请,当某个线程释放内存时又会回收进central。src/runtime/mcentral.go:mcentral定义了central数据结构:
lock: 线程间互斥锁,防止多线程读写冲突
spanclass : 每个mcentral管理着一组有相同class的span列表
nonempty: 指还有内存可用的span列表
empty: 指没有内存可用的span列表
nmalloc: 指累计分配的对象个数线程从central获取span步骤如下:
将span归还步骤如下:
从mcentral数据结构可见,每个mcentral对象只管理特定的class规格的span。事实上每种class都会对应一个mcentral,这个mcentral的集合存放于mheap数据结构中。src/runtime/mheap.go:mheap定义了heap的数据结构:
lock: 互斥锁
spans: 指向spans区域,用于映射span和page的关系
bitmap:bitmap的起始地址
arena_start: arena区域首地址
arena_used: 当前arena已使用区域的最大地址
central: 每种class对应的两个mcentral
从数据结构可见,mheap管理着全部的内存,事实上Golang就是通过一个mheap类型的全局变量进行内存管理的。mheap内存管理示意图如下:
系统预分配的内存分为spans、bitmap、arean三个区域,通过mheap管理起来。接下来看内存分配过程。
针对待分配对象的大小不同有不同的分配逻辑:
(0, 16B) 且不包含指针的对象: Tiny分配
(0, 16B) 包含指针的对象:正常分配
[16B, 32KB] : 正常分配
(32KB, -) : 大对象分配其中Tiny分配和大对象分配都属于内存管理的优化范畴,这里暂时仅关注一般的分配方法。
以申请size为n的内存为例,分配步骤如下:
Golang内存分配是个相当复杂的过程,其中还掺杂了GC的处理,这里仅仅对其关键数据结构进行了说明,了解其原理而又不至于深陷实现细节。1、Golang程序启动时申请一大块内存并划分成spans、bitmap、arena区域
2、arena区域按页划分成一个个小块。
3、span管理一个或多个页。
4、mcentral管理多个span供线程申请使用
5、mcache作为线程私有资源,资源来源于mcentral。
线程锁的原理:当对象获取锁时,它首先使自己的高速缓存无效,这样就可以保证直接从主内存中装入变量。
同样,在对象释放锁之前,它会刷新其高速缓存,强制使已做的任何更改都出现在主内存中。 这样,会保证在同一个锁上同步的两个线程看到在 synchronized 块内修改的变量的相同值。
一般来说,线程以某种不必让其他线程立即可以看到的方式(不管这些线程在寄存器中、在处理器特定的缓存中,还是通过指令重排或者其他编译器优化),不受缓存变量值的约束。
扩展资料:
线程锁在run()函数中使用QMutex实现同步,当多个线程访问共享变量时,使用lock/trylock和unlock将共享变量包裹,以保证同步访问共享变量。
如果不加锁将会在2秒后同时修改num变量,将会导致线程不按照我们的想法执行,当前线程锁定后,其他线程如果遇到共享变量将会等待解锁;
使用QMutex上锁解锁时,当代码提前退出有可能并未执行unlock(),若其他线程采用lock上锁会一直被阻塞,导致内存溢出。
前面,我们讲了map的用法以及原理 Golang中map的实现原理 ,但我们知道,map在并发读写的情况下是不安全。需要并发读写时,一般的做法是加锁,但这样性能并不高,Go语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map,今天,我们就来讲讲 sync.Map的用法以及原理
sync.Map与map不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构:
我们下来看下sync.Map结构体
结构体之间的关系如下图所示:
总结一下:
Load方法比较简单,总结一下:
总结如下:
锁的原理:
锁一般由锁芯、弹子、弹簧、锁舌、钥匙等几部分组成。其中锁芯分内锁芯和外锁芯,内锁芯是你插钥匙的地方;铜弹子分内弹子和外弹子,圆柱形,长短不一;弹簧是装在外锁芯的圆孔中顶住弹子;锁舌则是开锁时伸缩的部分;钥匙有不同高度的“牙花”对应不同长度的弹子。
知识点延伸:
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流