linux内核原子操作的实现

linux内核部件分析(二)——原子性操作atomic_t 在任何处理器平台下,都会有一些原子性操作,供操作系统使用,我们这里只讲x86下面的。在单处理器情况下,每条指令的执行都是原子性的,但在多处理器情况下,只有那些单独的读操作或写操作才是原子性的。为了弥补这一缺点,x86提供了附加的lock前缀,使带lock前缀的读修改写指令也能原子 阅读详情

所谓原子操作,就是“不可中断的一个或一系列操作”。

硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。在多处理器结构中(Symmetric Multi-Processor)就不同了,由于系统中有多个处理器独立运行,即使能在单条指令中完成的操作也有可能受到干扰。在X86平台生,CPU提供了在指令执行期间对总线加锁的手段。CPU上有一根引线#HLOCK pin连到北桥,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。对于其他平台的CPU,实现各不相同,有的是通过关中断来实现原子操作(sparc),有的通过CMPXCHG系列的指令来实现原子操作(IA64)。本文主要探讨X86平台下原子操作的实现。

软件级别的原子操作:软件级别的原子操作实现依赖于硬件原子操作的支持。

Linux内核提供了两组原子操作接口:一组是针对整数进行操作;另一组是针对单独的位进行操作。

1、原子整数操作

原子操作通常针对int或bit类型的数据,但是Linux并不能直接对int进行原子操作,而只能通过atomic_t的数据结构来进行。目前了解到的原因有两个。

一是在老的Linux版本,atomic_t实际只有24位长,低8位用来做锁。这是由于Linux是一个跨平台的实现,可以运行在多种 CPU上,有些 类型的CPU比如SPARC并没有原生的atomic指令支持,所以只能在32位int使用8位来做同步锁,避免多个线程同时访问。(最新版SPARC实现已经突破此限制)。 原子整数操作最常见的用途就是实现计数器。常见的用法是:

atomic_t use_cnt;

atomic_set(&use_cnt, 2);

atomic_add(4, &use_cnt);

atomic_inc(use_cnt);

在X86平台上,atomic_t定义如下:

[cpp]  view plain copy
  1. typedef struct {  
  2.     int counter;  
  3. } atomic_t;  
下面选取atomic_add来进行分析:
[cpp]  view plain copy
  1. static inline void atomic_add(int i, atomic_t *v)  
  2. {  
  3.     asm volatile(LOCK_PREFIX "addl %1,%0"  
  4.              : "+m" (v->counter)  
  5.              : "ir" (i));  
  6. }  
可以看到,atomic_add使用了gcc提供的内嵌汇编来实现,是用一个addl指令来实现增加操作。重点看一下LOCK_PREFIX宏,它就是上文提到的锁总线操作,也就是它保证了操作的原子性。LOCK_PREFIX定义如下:
[cpp]  view plain copy
  1. #define LOCK_PREFIX \  
  2.                 ".section .smp_locks,\"a\"\n"   \  
  3.                 "  .align 4\n"                  \  
  4.                 "  .long 661f\n" /* address */  \  
  5.                 ".previous\n"                   \  
  6.                 "661:\n\tlock; "  
展开后变成:
[cpp]  view plain copy
  1. .section .smp_locks,"a"  
  2.   .align 4  
  3.   .long 661f  
  4. .previous  
  5. 661:  
  6.         lock;  
逐条解释如下:
.section .smp_locks,"a"
下面的代码生成到 .smp_locks 段里,属性为"a", allocatable
  .align 4
四字节对齐
  .long 661f
生成一个整数,值为下面的 661 标号的实际地址,f 表示向前引用,如果 661 标号出现
在前面,要写 661b。
.previous
代码生成恢复到原来的段,也就是 .text
661:
数字标号是局部标号,5.3 Symbol Names
        lock;
开始生成指令,lock 前缀
这段代码汇编后,在 .text 段生成一条 lock 指令前缀 0xf0,在 .smp_locks 段生成四个字节的 lock 前缀的地址,链接的时候,所有的.smp_locks 段合并起来,形成一个所有 lock 指令地址的数组,这样统计 .smp_locks 段就能知道代码里有多少个加锁的指令被生成,猜测是为了调试目的。

搜索了一下,找到了相关引用处,当一个内核模块被加载时,会调用module_finalize函数:

[cpp]  view plain copy
  1. int module_finalize(const Elf_Ehdr *hdr,  
  2.             const Elf_Shdr *sechdrs,  
  3.             struct module *me)  
  4. {  
  5.     const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,  
  6.         *para = NULL;  
  7.     char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;  
  8.   
  9.     for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {   
  10.         if (!strcmp(".text", secstrings + s->sh_name))  
  11.             text = s;  
  12.         if (!strcmp(".altinstructions", secstrings + s->sh_name))  
  13.             alt = s;  
  14.         if (!strcmp(".smp_locks", secstrings + s->sh_name))  
  15.             locks= s;  
  16.         if (!strcmp(".parainstructions", secstrings + s->sh_name))  
  17.             para = s;  
  18.     }  
  19.   
  20.     if (alt) {  
  21.         /* patch .altinstructions */  
  22.         void *aseg = (void *)alt->sh_addr;  
  23.         apply_alternatives(aseg, aseg + alt->sh_size);  
  24.     }  
  25.     if (locks && text) {  
  26.         void *lseg = (void *)locks->sh_addr;  
  27.         void *tseg = (void *)text->sh_addr;  
  28.         alternatives_smp_module_add(me, me->name,  
  29.                         lseg, lseg + locks->sh_size,  
  30.                         tseg, tseg + text->sh_size);  
  31.     }  
  32.   
  33.     if (para) {  
  34.         void *pseg = (void *)para->sh_addr;  
  35.         apply_paravirt(pseg, pseg + para->sh_size);  
  36.     }  
  37.   
  38.     return module_bug_finalize(hdr, sechdrs, me);  
  39. }  
上面的代码说,如果模块有 .text 和 .smp_locks 段,就调这个来处理,做什么呢?

[cpp]  view plain copy
  1. void alternatives_smp_module_add(struct module *mod, char *name,  
  2.                  void *locks, void *locks_end,  
  3.                  void *text,  void *text_end)  
  4. {  
  5.     struct smp_alt_module *smp;  
  6.   
  7.     if (noreplace_smp)  
  8.         return;  
  9.   
  10.     if (smp_alt_once) {  
  11.         if (boot_cpu_has(X86_FEATURE_UP))  
  12.             alternatives_smp_unlock(locks, locks_end,  
  13.                         text, text_end);  
  14.         return;  
  15.     }  
  16.   
  17.     ........//省略无关代码  
  18. }  
上面的代码说,如果是单处理器(UP),就调这个:

[cpp]  view plain copy
  1. static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end)  
  2. {  
  3.     u8 **ptr;  
  4.     char insn[1];  
  5.   
  6.     if (noreplace_smp)  
  7.         return;  
  8.   
  9.     add_nops(insn, 1);  
  10.     for (ptr = start; ptr < end; ptr++) {  
  11.         if (*ptr < text)  
  12.             continue;  
  13.         if (*ptr > text_end)  
  14.             continue;  
  15.         text_poke(*ptr, insn, 1);  
  16.     };  
  17. }  
看到这里就能明白,这是内核配置了 smp,但是实际运行到单处理器上时,通过运行期间打补丁,根据 .smp_locks 里的记录,把 lock 指令前缀替换成 nop 以消除指令加锁的开销,这个优化真是极致了……,可能考虑很多用户直接使用的是配置支持 SMP 编译好的内核而特地对 x86/x64 做的这个优化。

2、原子位操作的实现

编写代码时,以如下的方式进行操作

unsigned long word = 0;

set_bit(0, &word); /*第0位被设置*/

set_bit(1, &word); /*第1位被设置*/

clear_bit(1, &word); /*第1位被清空*/

change_bit(0, &word); /*翻转第0位*/

为什么关注原子操作?
1)在确认一个操作是原子的情况下,多线程环境里面,我们可以避免仅仅为保护这个操作在外围加上性能开销昂贵的锁。
2)借助于原子操作,我们可以实现互斥锁。
3)借助于互斥锁,我们可以把一些列操作变为原子操作。

我们重点关注一下以下两个函数的实现:

[cpp]  view plain copy
  1. /** 
  2.  * clear_bit - Clears a bit in memory 
  3.  * @nr: Bit to clear 
  4.  * @addr: Address to start counting from 
  5.  * 
  6.  * clear_bit() is atomic and may not be reordered.  However, it does 
  7.  * not contain a memory barrier, so if it is used for locking purposes, 
  8.  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() 
  9.  * in order to ensure changes are visible on other processors. 
  10.  */  
  11. static inline void clear_bit(int nr, volatile void *addr)  
  12. {  
  13.     asm volatile(LOCK_PREFIX "btr %1,%0" : ADDR : "Ir" (nr));  
  14. }  
[cpp]  view plain copy
  1. /* 
  2.  * clear_bit_unlock - Clears a bit in memory 
  3.  * @nr: Bit to clear 
  4.  * @addr: Address to start counting from 
  5.  * 
  6.  * clear_bit() is atomic and implies release semantics before the memory 
  7.  * operation. It can be used for an unlock. 
  8.  */  
  9. static inline void clear_bit_unlock(unsigned nr, volatile void *addr)  
  10. {  
  11.     barrier();  
  12.     clear_bit(nr, addr);  
  13. }  
第一个clear_bit函数比较好理解,和上面atomic系列的函数实现类似。但是注意到clear_bit_unlock函数中多了一个barrier函数,这是什么操作呢?
这就是有名的“内存屏障“或”内存栅栏“操作,先来补充一下这方面的知识。

可以看一下barrier的定义:

[cpp]  view plain copy
  1. #define barrier() __asm__ __volatile__("": : :"memory")  

解释一下:__volatitle__是防止编译器移动该指令的位置或者把它优化掉。"memory",是提示编译器该指令对内存修改,防止使用某个寄存器中已经load 的内存的值。lock 前缀是让cpu 的执行下一行指令之前,保证以前的指令都被正确执行。

事实上,不止barrier,还有一个mb系列的函数也起着内存屏障的功能:
[cpp]  view plain copy
  1. #include <asm/system.h>  
  2. "void rmb(void);"  
  3. "void wmb(void);"  
  4. "void mb(void);"  

这些函数在已编译的指令流中插入硬件内存屏障,具体的插入方法是平台相关的。rmb(读内存屏障)保证了屏障之前的读操作一定会在后来的读操作执行之前完成。wmb保证写操作不会乱序,mb 指令保证了两者都不会。这些函数都是 barrier 函数的超集。解释一下:编译器或现在的处理器常会自作聪明地对指令序列进行一些处理,比如数据缓存,读写指令乱序执行等等。如果优化对象是普通内存,那么一般会提升性能而且不会产生逻辑错误。但如果对I/O 操作进行类似优化很可能造成致命错误。所以要使用内存屏障,以强制该语句前后的指令以正确的次序完成。

其实在指令序列中放一个wmb 的效果是使得指令执行到该处时,把所有缓存的数据写到该写的地方,同时使得wmb 前面的写指令一定会在wmb后面 的写指令之前执行。

回到上面的函数,当clear_bit函数不用于实现锁的目的时,不用给它加上内存屏障(我的理解:不管是不是读到最新的数据,这一位就是要清零,不管加不加内存屏障,结果都是一样的);而当用于实现锁的目的时,必须使用clear_bit_unlock函数,其实现中使用了内存屏障,以此来确保此处的修改能在其他CPU上看到(我的理解:加锁操作就是为了在多个CPU间进行同步的目的,所以要避免寄存器优化,其他CPU每次都读内存这样才能看到最新的变化,这块不是太明白)。这种操作也叫做serialization,即在执行这条指令前,CPU必须要完成前面所有对memory的访问指令(read and write),这样是为了避免编译器进行某些优化。

同样使用serialization操作的还有test_and_set_bit函数:

[cpp]  view plain copy
  1. /** 
  2.  * test_and_set_bit - Set a bit and return its old value 
  3.  * @nr: Bit to set 
  4.  * @addr: Address to count from 
  5.  * 
  6.  * This operation is atomic and cannot be reordered. 
  7.  * It also implies a memory barrier. 
  8.  */  
  9. static inline int test_and_set_bit(int nr, volatile void *addr)  
  10. {  
  11.     int oldbit;  
  12.   
  13.     asm volatile(LOCK_PREFIX "bts %2,%1\n\t"  
  14.              "sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");  
  15.   
  16.     return oldbit;  
  17. }  
解释一下:
1)memory 强制gcc 编译器假设RAM 所有内存单元均被汇编指令修改,这样cpu 中的registers 和cache 中已缓存的内存单元中的数据将作废。cpu 将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu 又将registers,cache 中的数据用于去优化指令,而避免去访问内存。

2)sbb  $0,0(%%esp)表示将数值0 减到esp 寄存器中,而该寄存器指向栈顶的内存单元。减去一个0,esp 寄存器的数值依然不变。即这是一条无用的汇编指令。在此利用这条无价值的汇编指令来配合lock 指令,在__asm__,__volatile__,memory 的作用下,用作cpu 的内存屏障。

这种写法和前面的clear_bit_unlock中先写一个barrier函数,再写一个正常内嵌汇编函数的功能是一样的。

2.2.1 GNU C内嵌汇编语言 一个64位操作系统的实现 阅读详情

相关推荐

Linux内核实现原子性操作cmpxchg指令的理解

cmpxchg这个指令是为了

个人博客 4603

Linux内核原子操作 原理

摘自:http://ilinuxkernel.com/?p=1158 本文基linux内核版本 2.6.32-131.17.1.el6.i686源码。 1、原子读、赋值 00016: /** 00017:  *atomic_read-readatomicvariable 00018:  * @v:pointeroftypeatomic_t 00019:  * 00020:  *Ato

向往大海专栏 3309

TX 的 LOL(Local Oscillator Leakage,本振泄露)

项目内容LOL 是什么本振残留在 TX 输出中心频率上的杂散主要原因IQ 失衡、硬件不完美、零中频架构影响杂散、干扰、性能劣化、安全问题解决方法初始化校准 + 跟踪校准(AD9371 支持)检测手段频谱仪、回环检测、ADC ILA 抓取。

weixin_41230430的博客 2044

set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理

set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理

qq_27392987的博客 2788

Nginx下ModSecurity模块安装详细教程

本文提供了在Nginx 1.28.0上安装ModSecurity v3的完整教程。首先需安装编译依赖,然后从源码编译安装ModSecurity库并设置优化参数。接着编译Nginx动态模块并配置加载。核心配置包括设置规则引擎、日志路径及性能优化参数。安装OWASP核心规则集后,在Nginx站点配置中启用ModSecurity。最后测试规则有效性并给出性能优化建议,如规则排除、精简规则集等。整个过程包含详细的命令和配置示例,确保安全防护功能正常运作。

深山技术宅的博客 1781

SQL中的时间计算:员工每日工作时长

摘要:本文介绍了一个使用SQL查询计算员工每日工作时长的实用方法。通过分析包含员工打卡记录的数据库表,利用CTE(公共表表达式)将日期分组,计算最早和最晚打卡时间差,最终以"小时:分钟"格式输出工作时长。该方法适用于每日两次打卡的场景,并提示了处理漏打卡等特殊情况时的注意事项,为企业考勤管理提供了有效的数据支持方案。(148字)

m0_74337424的博客 412

原子性操作atomic_t

内核定义了atomic_t 数据类型,作为对整数计数器的原子操作的基础。 各个CPU平台有各自的原子操作实现方式,基本都是通过汇编实现的。  原子操作 原子操作是Linux中提供的一种实现同步的方法,所谓原子操作是指某一操作在执行过程中是不可以被打断的,它要么全部执行完毕,要么就一点也不执行。也就是说原子操作是绝对不会出现该操作执行了一半,内核又去执行其他操作的情况。 原子操作分为原子位

被遗忘的前辈 1万+

uniapp - 使用web-view加载本地网页vue页面,用webview导入本地网页,uniAPP中使用web-view加载的本地及远程vue页面+双向通讯功能(兼容微信小程序、安卓苹果APP)

uniapp的App端web-view加载本地html,uniapp微信小程序webview加载本地HTML文件,在uniAPP中使用web-view加载的本地及远程vue页面且进行双向通讯,uni-app的web-view组件,支持加载远程网页,在app环境下,还支持加载本地HTML页面。uniapp WebView组件实现本地网页加载与通讯传值,uniAPP如何内嵌webView引入本地的vue网页示例代码,uniapp在web-view加载的本地及远程HTML中调用uni的API及网页和vue页面跳转

🏆 前端领域优质创作者 5226

【Linux】linux内核原子操作的实现

所谓原子操作,就是“不可中断的一个或一系列操作”。 硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。在多处理器结构中(Symmetric Multi-Processor)就不同了,由于系统中有多个处理器独立运行,即使能在单条指令中完成的操作也有可能受到干扰。在X86平台生,CPU提供了在指令执行

AG的博客 1482

在windows系统上使用codex出现应用程序无法正常启动(0xc0000022)的解决方案

本文主要介绍了在windows系统上使用codex出现应用程序无法正常启动(0xc0000022)的解决方案,希望能对使用codex的同学们有所帮助。 文章目录 1. 问题描述 2. 原因分析 3. 解决方案

weixin_43178406的博客 10万+

原理和代码解读:用Diffusion Models高清图像修复(Image Inpainting)

在最近的Diffusion Models应用中,Image Inpainting+ControlNet/Lora等工作在模特衣服生成、家居场景重建等场景中得到了广泛的应用。这篇博客主要介绍Diffusion Models如何在修复高清图像的。

沉迷单车的追风少年 2495

int linux 原子操作_在Linux内核中读写原子操作实现

Recently I've peeked into the Linux kernel implementation of an atomic read and write and a few questions came up.First the relevant code from the ia64 architecture:typedef struct {int counter;} atomi...

weixin_30878135的博客 210

【原理图PCB专题】Cadence 17.4版本原理图及PCB 模块复用

在我们设计复杂板卡的时候,往往会遇到一部分电路被反复使用的情况。Cadence允许设计者一开始就将复用模块设计好,以后只要直接调用复用模块就可以直接用以设计更复杂的电路板了。这对于大规模集成设计无疑是非常好的选择,它不仅让设计者不必花费时间在相同模块反复设计上,更有利于电路的模块化设计。

一点硬件 2015

int linux 原子操作,在Linux内核中读写原子操作实现

Recently I've peeked into the Linux kernel implementation of an atomic read and write and a few questions came up.First the relevant code from the ia64 architecture:typedef struct {int counter;} atomi...

weixin_39754831的博客 99

芯片ATE测试PAT(Part Average Testing)学习总结-20250916

文章摘要:零件平均测试(PAT)是半导体制造中基于统计学的质量控制方法,分为静态和动态两种类型。静态PAT通过预先设定的固定限值(每6-8批次更新)筛选异常芯片,计算采用稳健平均值和四分位间距。动态PAT则根据实时数据调整限值,能更精确识别异常而不误判合格芯片。两种方法均采用"均值±6倍标准差"的计算公式,但动态PAT具有更好的适应性和准确性。该方法通过统计分析提高了芯片产品的质量和可靠性。

歌颂苦难的行为是无耻的; 1190

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

linux内核对原子操作的实现

/* * ARMv6 UP and SMP safe atomic ops. We use load exclusive and * store exclusive to ensure that these are atomic. We may loop * to ensure that the update happens. */ #define ATOMIC_OP(op, c_op, asm_op) \ static inline void arch_atomic_##op(in.

u010843408的专栏 961

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Linux内核原子操作实现原理几问几答

用锁当然可以实现独占原子性的操作,但是要么引发调度,要么自旋空转,对于简单的内存操作没有必要。cmpxchg在各个平台都有各自的实现,且其实现的方式都以原子性指令实现,比如x86架构的cmpxchg指令,ARM64架构的ldxr和stxr指令。首先,armv8.0架构上可以调用casx指令,但是个人理解应该是伪指令的形式实现的,本质上还是利用ldxr和stxr实现的。高并发访问的时候可以根据需求使用原子操作API,可以使用共用定义基于cmpxchg实现的API也可以使用架构优化的版本。

906

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

linux原子操作实现原理,Linux2.6内核的原子操作的实现

Linux2.6.18之后,删除了和,GCC提供了内置的原子操作函数,更适合用户态的程序使用。现在atomic.h在内核头文件中,不在gcc默认搜索路径下,即使像下面这样强行指定路径,还是会出现编译错误。1. #includegcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作,可以对1,2,4或8字节长度的数值类型或指针进行原子操作,其声明如下1...

weixin_30016961的博客 234

Linux内核原子操作实战:从命名规则到ARMv8架构实现

本文深入解析Linux内核原子操作的命名规则、使用场景与ARMv8架构下的实现差异。通过剖析函数命名逻辑(如_fetch取旧值、_return取新值)和内存屏障语义(acquire/release),指导开发者根据并发需求选择正确函数。重点对比了ARMv8.1 LSE指令集与LL/SC机制的性能差异,为编写高效、正确的内核同步代码提供实战指导。

4k5l6j7h8的博客 725

Linux内核中的原子操作的实现

原子操作主要使用汇编语言实现,因为使用到总线锁和寄存器等操作。

陈嘉怡的专栏 2006

Linux内核原子操作(2)接口与实现

处理器在提供了硬件级别的原子操作保障后,软件可以基于硬件机制实现软件级别的原子操作接口,提供给软件模块使用。

Aspiresky的专栏 1006

Linux2.6内核的原子操作的实现

Linux2.6.18之后,删除了和,GCC提供了内置的原子操作函数,更适合用户态的程序使用。现在atomic.h在内核头文件中,不在gcc默认搜索路径下,即使像下面这样强行指定路径,还是会出现编译错误。 1.  #include  gcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作,可以对1,2,4或8

740

Linux内核原子操作实战:从命名规则到ARMv8指令级实现(附避坑指南)

本文深入解析Linux内核原子操作的命名规则、内存序语义及其在ARMv8架构下的实现机制。通过对比传统的LL/SC循环与现代LSE指令集的性能差异,并结合实战案例,为开发者提供了一份详尽的并发编程避坑指南,帮助编写更健壮、高效的内核代码。

sat99的博客 445
上一篇: 单链表的逆置-C++实现
下一篇: C语言的预处理问题
计算机与认知
博客等级 码龄14年 31粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值