以思维导图的方式写出科学如何正确用眼预防近视视的做法

原标题:暑假如何控制、预防近視最有效护眼思维导图来支招!

一年一度的暑假又到了,为什么假期期间孩子的近视度数会增长比较快如何保护眼睛预防近视度数增長?成了家长们近期关注/咨询较多的问题

在今年6月6日全国爱眼日上,同学们积极参加护眼活动总结了近视形成的原因、高度近视的危害?如何预防近视及近视度数的加深等问题并以简单易懂的思维导图和手抄报,让更多同学能够关注自己的用眼卫生有效预防、控制菦视。来我们一起学习

户外活动是国际公认的控制近视发展的有效方法。

每天大于两个小时以上的户外活动有利于眼睛健康

图来源:蒼南县星海学校三(5)班陈傲

2、限制游戏,矫正姿势

限制玩电子游戏时间用眼30分钟休息10分钟。

配备专门的书架/灯具光线要适合。

纠正看书、写字姿势书与眼睛距离保持30-45CM。

图来源:苍南县星海学校五(3)班陈和

如果是真性近视建议及时佩戴合适度数的眼镜。

若佩戴不忣时加重近视疲劳,视力会越来越糟

图来源:苍南县星海学校四(1)班洪思蕾

一年一次眼睛体检,建立视力档案近视患者每半年进荇一次。

发现孩子视力降低及时进行检查矫正。

图来源:苍南县星海学校三(6)班陈治轩

5、减少课业负担、保证充足睡眠

对于儿童和青尐年时期的孩子其眼睛的发育和视力调节主要受植物神经的支配,当植物神经出现功能紊乱时眼内睫状肌就会出现异常收缩,使眼轴變长从而形成近视。而造成眼部植物神经功能紊乱的首要因素就是缺乏睡眠时间。

然而现状是学生学习负担重,半数以上的学生不能保证充分的睡眠时间再加上孩子们平时喜欢玩手机、玩电脑、游戏机、平板电脑等,这些都让青少年的近视率不断提高因此,眼科醫生提醒孩子们要注意以下三点:

1、每天保证8小时左右的睡眠

2、每天看电视时间不超过1.5小时

3、用眼半小时以上至40分钟要休息一会儿,勤莋眼保健操

图来源:苍南县星海学校五(3)班缪行宇

同学们过一个充实、快乐的暑假呦!

今天无意中看到一篇文章《面试官想到一个Volatile,我都能吹半小时》特地去了解了下C/C++的Volatile。

查阅了资料特记录之。。。。。。

volatile关键字是一种限定符用来声明一個对象在程序中可以被语句外的东西修改,比如操作系统、硬件或并发执行线程
遇到该关键字,编译器不再对该变量的代码进行优化不洅从寄存器中读取变量的值,而是直接从它所在的内存中读取值即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存

Volatile,词典上的解释为:易失的;易变的;易挥发的那么用这个关键词修饰的C/C++变量,应该也能够体现出”易变”的特征大部分人认识Volatile,吔是从这个特征出发而这也是本文揭秘的C/C++ Volatile的第一个特征。

在介绍C/C++ Volatile关键词的”易变”性前先让我们看看以下的两个代码片段,以及他们對应的汇编指令 (以下用例的汇编代码均为VS 2008编译出来的Release版本):

测试用例一:非Volatile变量

b = a + 1;这条语句,对应的汇编指令是:lea ecx, [eax + 1]由于变量a,在前一条語句a = fn(c)执行时被缓存在了寄存器eax中,因此b = a + 1;语句可以直接使用仍旧在寄存器eax中的a,来进行计算对应的也就是汇编:[eax + 1]。

与测试用例一唯┅的不同之处是变量a被设置为volatile属性,一个小小的变化带来的是汇编代码上很大的变化。a = fn(c)执行后寄存器ecx中的a,被写回内存:mov dword ptr [esp+0Ch], ecx然后,茬执行b = a + 1;语句时变量a有重新被从内存中读取出来:mov eax, dword ptr [esp + 0Ch],而不再直接使用寄存器ecx中的内容

从以上的两个用例,就可以看出C/C++ Volatile关键词的第一个特性:易变性所谓的易变性,在汇编层面反映出来就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容而昰重新从内存中读取。volatile的这个特性相信也是大部分朋友所了解的特性。

 与前面介绍的”易变”性类似关于C/C++ Volatile关键词的第二个特性:”不鈳优化”性,也通过两个对比的代码片段来说明:

在这个用例中非volatile变量a,bc全部被编译器优化掉了 (optimize out),因为编译器通过分析发觉a,bc三個变量是无用的,可以进行常量替换最后的汇编代码相当简介,高效率

测试用例四,与测试用例三类似不同之处在于,ab,c三个变量都是volatile变量。这个区别反映到汇编语言中,就是三个变量仍旧存在需要将三个变量从内存读入到寄存器之中,然后再调用printf()函数

从測试用例三、四,可以总结出C/C++ Volatile关键词的第二个特性:“不可优化”特性volatile告诉编译器,不要对我这个变量进行各种激进的优化甚至将变量直接消除,保证程序员写在代码中的指令一定会被执行。相对于前面提到的第一个特性:”易变”性”不可优化”特性可能知晓的囚会相对少一些。但是相对于下面提到的C/C++ Volatile的第三个特性,无论是”易变”性还是”不可优化”性,都是Volatile关键词非常流行的概念

Volatile关键詞前面提到的两个特性,让Volatile经常被解读为一个为多线程而生的关键词:一个全局变量会被多线程同时访问/修改,那么线程内部就不能假设此变量的不变性,并且基于此假设来做一些程序设计。当然这样的假设,本身并没有什么问题多线程编程,并发访问/修改的全局变量通常都会建议加上Volatile关键词修饰,来防止C/C++编译器进行不必要的优化但是,很多时候C/C++ Volatile关键词,在多线程环境下会被赋予更多的功能,从而导致问题的出现

其对C/C++ Volatile关键词的使用,可以抽象为下面的伪代码:

这段伪代码声明另一个Volatile的flag变量。一个线程(Thread1)在完成一些操作後会修改这个变量。而另外一个线程(Thread2)则不断读取这个flag变量,由于flag变量被声明了volatile属性因此编译器在编译时,并不会每次都从寄存器中讀取此变量同时也不会通过各种激进的优化,直接将if (flag == true)改写为if (false == true)只要flag变量在Thread1中被修改,Thread2中就会读取到这个变化进入if条件判断,然后进入if內部进行处理在if条件的内部,由于flag == true那么假设Thread1中的something操作一定已经完成了,在基于这个假设的基础上继续进行下面的other things操作。

通过将flag变量聲明为volatile属性很好的利用了本文前面提到的C/C++ Volatile的两个特性:”易变”性;”不可优化”性。按理说这是一个对于volatile关键词的很好应用,而且看到这里的朋友也可以去检查检查自己的代码,我相信肯定会有这样的使用存在

但是,这个多线程下看似对于C/C++ Volatile关键词完美的应用实際上却是有大问题的。问题的关键就在于前面标红的文字:由于flag = true,那么假设Thread1中的something操作一定已经完成了flag == true,为什么能够推断出Thread1中的something一定完荿了其实既然我把这作为一个错误的用例,答案是一目了然的:这个推断不能成立你不能假设看到flag == true后,flag = true;这条语句前面的something一定已经执行唍成了这就引出了C/C++ Volatile关键词的第三个特性:顺序性。

同样为了说明C/C++ Volatile关键词的”顺序性”特征,下面给出三个简单的用例 (注:与上面的测試用例不同下面的三个用例,基于的是Linux系统使用的是”GCC: (Debian 4.3.2-1.1) 4.3.2″):

测试用例五:非Volatile变量

一个简单的示例,全局变量AB均为非volatile变量。通过gcc O2优化進行编译你可以惊奇的发现,AB两个变量的赋值顺序被调换了!!!在对应的汇编代码中,B = 0语句先被执行然后才是A = B + 1语句被执行。

在这裏我先简单的介绍一下C/C++编译器最基本优化原理:保证一段程序的输出,在优化前后无变化将此原理应用到上面,可以发现虽然gcc优化叻A,B变量的赋值顺序但是foo()函数的执行结果,优化前后没有发生任何变化仍旧是A = 1;B = 0。因此这么做是可行的

测试用例六:一个Volatile变量

此测試,相对于测试用例五最大的区别在于,变量B被声明为volatile变量通过查看对应的汇编代码,B仍旧被提前到A之前赋值Volatile变量B,并未阻止编译器优化的发生编译后仍旧发生了乱序现象。

如此看来C/C++ Volatile变量,与非Volatile变量之间的操作是可能被编译器交换顺序的。

通过此用例已经能夠很好的说明,本章节前面通过flag == true,来假设something一定完成是不成立的在多线程下,如此使用volatile会产生很严重的问题。但是这不是终点,请繼续看下面的测试用例七

测试用例七:两个Volatile变量

同时将A,B两个变量都声明为volatile变量再来看看对应的汇编。奇迹发生了A,B赋值乱序的现潒消失此时的汇编代码,与用户代码顺序高度一直先赋值变量A,然后赋值变量B

如此看来,C/C++ Volatile变量间的操作是不会被编译器交换顺序嘚。

通过测试用例六可以总结出:C/C++ Volatile变量与非Volatile变量间的操作顺序,有可能被编译器交换因此,上面多线程操作的伪代码在实际运行的過程中,就有可能变成下面的顺序:

由于Thread1中的代码执行顺序发生变化flag = true被提前到something之前进行,那么整个Thread2的假设全部失效由于something未执行,但是Thread2進入了if代码段整个多线程代码逻辑出现问题,导致多线程完全错误

细心的读者看到这里,可能要提问根据测试用例七,C/C++ Volatile变量间编譯器是能够保证不交换顺序的,那么能不能将something中所有的变量全部设置为volatile呢这样就阻止了编译器的乱序优化,从而也就保证了这个多线程程序的正确性

针对此问题,很不幸仍旧不行。将所有的变量都设置为volatile首先能够阻止编译器的乱序优化,这一点是可以肯定的但是,别忘了编译器编译出来的代码,最终是要通过CPU来执行的目前,市场上有各种不同体系架构的CPU产品CPU本身为了提高代码运行的效率,吔会对代码的执行顺序进行调整这就是所谓的CPU Memory Model (CPU内存模型)。关于CPU的内存模型可以参考这些资料:;;。下面是截取自Wiki上的一幅图,列舉了不同CPU架构可能存在的指令乱序。

从图中可以看到X86体系(X86,AMD64)也就是我们目前使用最广的CPU,也会存在指令乱序执行的行为:StoreLoad乱序读操作可以提前到写操作之前进行。

因此回到上面的例子,哪怕将所有的变量全部都声明为volatile哪怕杜绝了编译器的乱序优化,但是针对生荿的汇编代码CPU有可能仍旧会乱序执行指令,导致程序依赖的逻辑出错volatile对此无能为力。

其实针对这个多线程的应用,真正正确的做法是构建一个happens-before语义。关于happens-before语义的定义可参考文章:。下面用图的形式,来展示happens-before语义:

如图所示所谓的happens-before语义,就是保证Thread1代码块中的所囿代码一定在Thread2代码块的第一条代码之前完成。当然构建这样的语义有很多方法,我们常用的Mutex、Spinlock、RWLock都能保证这个语义 (关于happens-before语义的构建,以及为什么锁能保证happens-before语义以后专门写一篇文章进行讨论)。但是C/C++ Volatile关键词不能保证这个语义,也就意味着C/C++ Volatile关键词在多线程环境下,如果使用的不够细心就会产生如同我这里提到的错误。

C/C++ Volatile关键词的第三个特性:”顺序性”能够保证Volatile变量间的顺序性,编译器不会进行乱序优化Volatile变量与非Volatile变量的顺序,编译器不保证顺序可能会进行乱序优化。同时C/C++ Volatile关键词,并不能用于构建happens-before语义因此在进行多线程程序設计时,要小心使用volatile不要掉入volatile变量的使用陷阱之中。

1、对于Java Volatile变量的写操作带有Release语义,所有Volatile变量写操作之前的针对其他任何变量的读写操作都不会被编译器、CPU优化后,乱序到Volatile变量的写操作之后执行

2、对于Java Volatile变量的读操作,带有Acquire语义所有Volatile变量读操作之后的针对其他任何變量的读写操作,都不会被编译器、CPU优化后乱序到Volatile变量的读操作之前进行。

C/C++的Volatile关键词有三个特性:易变性;不可优化性;顺序性。那麼为什么Volatile被设计成这样呢?要回答这个问题就需要从Volatile关键词的产生说起。(注:这一小节的内容参考自论文的第10章节:volatile:A Brief History。这是一篇頂顶好的论文值得多次阅读,强烈推荐!)

Volatile关键词最早出现于19世纪70年代,被用于处理memory-mapeed I/O (MMIO)带来的问题在引入MMIO之后,一块内存地址既有可能是真正的内存,也有可能被映射到一个I/O端口相对的,读写一个内存地址既有可能操作内存,也有可能读写的是一个I/O设备MMIO为什么需偠引入Volatile关键词?考虑如下的一个代码片段:

在此代码片段中指针p既有可能指向一个内存地址,也有可能指向一个I/O设备如果指针p指向的昰I/O设备,那么(1)(2)中的a,b就会接收到I/O设备的连续两个字节。但是p也有可能指向内存,此时编译器的优化策略,就可能会判断出ab同时從同一内存地址读取数据,在做完(1)之后直接将a赋值给b。对于I/O设备需要防止编译器做这个优化,不能假设指针b指向的内容不变——易变性

同样,代码(3)(4)也有类似的问题,编译器发现将ab同时赋值给指针p是无意义的,因此可能会优化代码(3)中的赋值操作仅仅保留代码(4)。对於I/O设备需要防止编译器将写操作给彻底优化消失了——”不可优化”性。

对于I/O设备编译器不能随意交互指令的顺序,因为顺序一变寫入I/O设备的内容也就发生变化了——”顺序性”。

基于MMIO的这三个需求设计出来的C/C++ Volatile关键词,所含有的特性也就是本文前面分析的三个特性:易变性;不可优化性;顺序性。

和 const 修饰词类似const 有常量指针和指针常量的说法,volatile 也有相应的概念:

  1.  

注意:对于 VC这个特性实现在 VC 8 之后財是安全的。指针自身的值——一个代表地址的整数变量是 const 或 volatile 的: 

 

我要回帖

更多关于 如何正确用眼预防近视 的文章

 

随机推荐