当前位置: 首页 > news >正文

网站源码防盗原理银川商城网站建设

网站源码防盗原理,银川商城网站建设,遵义祥云平台网站建设,仿99健康网网站源码系列文章iOS 汇编入门教程(一)ARM64 汇编基础iOS 汇编入门教程(二)在 Xcode 工程中嵌入汇编代码iOS 汇编入门教程(三)汇编中的 Section 与数据存取iOS 汇编教程(四)基于 LLDB 动态调试快速分析系统函数的实现iOS 汇编教程(五)Objc Block 的内存布局和汇编表示前言具有 ARM 体系… 系列文章iOS 汇编入门教程(一)ARM64 汇编基础iOS 汇编入门教程(二)在 Xcode 工程中嵌入汇编代码iOS 汇编入门教程(三)汇编中的 Section 与数据存取iOS 汇编教程(四)基于 LLDB 动态调试快速分析系统函数的实现iOS 汇编教程(五)Objc Block 的内存布局和汇编表示前言具有 ARM 体系结构的机器拥有相对较弱的内存模型这类 CPU 在读写指令重排序方面具有相当大的自由度为了保证特定的执行顺序来获得确定结果开发者需要在代码中插入合适的内存屏障以防止指令重排序影响代码逻辑[1]。本文会介绍 CPU 指令重排的意义和副作用并通过一个实验验证指令重排对代码逻辑的影响随后介绍基于内存屏障的解决方案以及在 iOS 开发中有关指令重排的注意事项。指令重排简介以 ARM 为体系结构的 CPU 在执行指令时在遇到写操作时如果未获得缓存段的独占权限需要基于缓存一致性协议与其他核协商等待直到获得独占权限时才能完成这条指令的执行再或者在执行乘法指令时遇到乘法器繁忙的情况也需要等待。在这些情况下为了提升程序的执行速度CPU 会优先执行一些没有前序依赖的指令。一个例子看下面一段简单的程序; void acc(int *counter, int *flag);_acc:ldr x8, [x0]add x8, x8, #1str x8, [x0]ldr x9, [x1]mov x9, #1str x9, [x1]ret这段代码将 counter 的值 1并将 flag 置为 1按照正常的代码逻辑CPU 先从内存中读取 counter (x0) 的值累加后回写随后读取 flag (x1) 的值置位后回写。但是如果 x0 所在的内存未命中缓存会带来缓存载入的等待再或者回写时无法获取到缓存段的独占权为了保证多核的缓存一致性也需要等待此时如果 x1 对应的内存有缓存段则可以优先执行 ldr x9, [x1]同时由于对 x9 的操作和对 x1 所在内存的操作不依赖于对 x8 和 x0 所在内存的操作后续指令也可以优先执行因此 CPU 乱序执行的顺序可能变成如下这样ldr x9, [x1]mov x9, #1str x9, [x1]ldr x8, [x0]add x8, x8, #1str x8, [x0]甚至如果写操作都需要等待还可能将写操作都滞后ldr x9, [x1]mov x9, #1ldr x8, [x0]add x8, x8, #1str x9, [x1]str x8, [x0]再或者如果加法器繁忙又会带来全新的执行顺序当然这一切都要建立在被重新排序的指令之间不能相互他们依赖执行的结果。副作用指令重排大幅度提升了 CPU 的执行速度但凡事都有两面性虽然在 CPU 层面重排的指令能保证运算的正确性但在逻辑层面却可能带来错误。比如常见的自旋锁场景我们可能设置一个 bool 类型的 flag 来自旋等待某异步任务的完成在这种情况下一般是在任务结束时对 flag 置位如果置位 flag 的语句被重排到异步任务语句的中间将会带来逻辑错误。下面我们会通过一个实验来直观展示指令重排带来的副作用。一个实验在下面的代码中我们设置了两个线程一个执行运算并在运算结束后置位 flag另一个线程自旋等待 flag 置位后读取结果。我们首先定义一个保存运算结果的结构体。typedef struct FlagsCalculate { int a; int b; int c; int d; int e; int f; int g;} FlagsCalculate;为了更快的复现重排带来的错误我们使用了多个 flag 位存储在结构体的 e, f, g 三个成员变量中同时 a, b, c, d 作为运算结果的存储变量int getCalculated(FlagsCalculate *ctx) { while (ctx-e 0 || ctx-f 0 || ctx-g 0); return ctx-a ctx-b ctx-c ctx-d;}为了更快的触发未命中缓存我们使用了多个全局变量为了模拟加法器和乘法器繁忙我们采用了密集的运算int mulA 15;int mulB 35;int divC 2;int addD 20;void calculate(FlagsCalculate *ctx) { ctx-a (20 * mulA - mulB) / divC; ctx-b 30 addD; for (NSInteger i 0; i 10000; i) { ctx-a i * mulA - mulB; ctx-a * divC; ctx-b i * mulB / mulA - mulB; ctx-b / divC; } ctx-c mulA mulB * divC 120; ctx-d addD mulA mulB 5; ctx-e 1; ctx-f 1; ctx-g 1;}接下来我们将他们封装在 pthread 线程的执行函数内void* getValueThread(void *arg) { pthread_setname_np(getValueThread); FlagsCalculate *ctx (FlagsCalculate *)arg; int val getCalculated(ctx); assert(val -276387); return NULL;}void* calValueThread(void *arg) { pthread_setname_np(calValueThread); FlagsCalculate *ctx (FlagsCalculate *)arg; calculate(ctx); return NULL;}void newTest() { FlagsCalculate *ctx (FlagsCalculate *)calloc(1, sizeof(struct FlagsCalculate)); pthread_t get_t, cal_t; pthread_create(get_t, NULL, getValueThread, (void *)ctx); pthread_create(cal_t, NULL, calValueThread, (void *)ctx); pthread_detach(get_t); pthread_detach(cal_t);}每次调用 newTest 即开始一轮新的实验在 flag 置位未被乱序执行的情况下最终的运算结果是 -276387通过短时间内不断并发执行实验观察是否遇到断言即可判断是否由重排引发了逻辑异常while (YES) { newTest();}笔者在一个 iOS Empty Project 中添加上述代码并将其运行在一台 iPhone XS Max 上约 10 分钟后遇到了断言错误显然这是由于乱序执行导致的 flag 全部被提前置位从而导致异步线程获取到的执行结果错误通过实验我们验证了上面的理论。答疑解惑看到这里你可能惊出一身冷汗开始回忆起自己职业生涯中写过的类似逻辑也许线上有很多正在运行但从来没出过问题这又是为什么呢在 iOS 开发中我们常使用 GCD 作为多线程开发的框架这类 High Level 的多线程模型本身已经提供好了天然的内存屏障来保证指令的执行顺序因此可以大胆的去写上述逻辑而不用在意指令重排这也是我们使用 pthread 来进行上述实验的原因。到这里你也应该意识到如果采用 Low Level 的多线程模型来进行开发时一定要注意指令重排带来的副作用下面我们将介绍如何通过内存屏障来避免指令重排对逻辑的影响。内存屏障简介内存屏障是一条指令它能够明确地保证屏障之前的所有内存操作均已完成(可见)后才执行屏障后的操作但是它不会影响其他指令(非内存操作指令)的执行顺序[3]。因此我们只要在 flag 置位前放置内存屏障即可保证运算结果全部写入内存后才置位 flag进而也就保证了逻辑的正确性。放置内存屏障我们可以通过内联汇编的形式插入一个内存屏障void calculate(FlagsCalculate *ctx) { ctx-a (20 * mulA - mulB) / divC; ctx-b 30 addD; for (NSInteger i 0; i 10000; i) { ctx-a i * mulA - mulB; ctx-a * divC; ctx-b i * mulB / mulA - mulB; ctx-b / divC; } ctx-c mulA mulB * divC 120; ctx-d addD mulA mulB 5; __asm__ __volatile__(dmb sy); ctx-e 1; ctx-f 1; ctx-g 1;}随后继续刚才的试验可以发现断言不会再触发异常内存屏障限制了 CPU 乱序执行对正常逻辑的影响。volatile 与内存屏障我们常常听说 volatile 是一个内存屏障那么它的屏障作用是否与上述 DMB 指令一致呢我们可以试着用 volatile 修饰 3 个 flag再做一次实验typedef struct FlagsCalculate { int a; int b; int c; int d; volatile int e; volatile int f; volatile int g;} FlagsCalculate;结果最后触发了断言异常这是为何呢因为 volatile 在 C 环境下仅仅是编译层面的内存屏障仅能保证编译器不优化和重排被 volatile 修饰的内容但是在 Java 环境下 volatile 具有 CPU 层面的内存屏障作用[4]。不同环境表现不同这也是 volatile 让我们如此费解的原因。在 C 环境下volatile 常常用来保证内联汇编不被编译优化和改变位置例如我们通过内联汇编放置一个编译层面的内存屏障时通过 __volatile__ 修饰汇编代码块来保证内存屏障的位置不被编译器改变__asm__ __volatile__( ::: memory);总结到这里相信你对指令重排和内存屏障有了更加清晰的认识同时对 volatile 的作用也更加明确了希望本文能对大家有所帮助。参考资料[1]缓存一致性(Cache Coherency)入门: https://www.infoq.cn/article/cache-coherency-primer[2]CPU Reordering – What is actually being reordered?: https://mortoray.com/2010/11/18/cpu-reordering-what-is-actually-being-reordered/[3]ARM Information Center - DMB, DSB, and ISB: http://infocenter.arm.com/help/index.jsp?topic/com.arm.doc.dui0489c/CIHGHHIE.html[4]volatile 与内存屏障总结: https://zhuanlan.zhihu.com/p/43526907
http://www.pierceye.com/news/200704/

相关文章:

  • 济南网站制作定制公司wordpress重新安装主题
  • python 网站开发教程怎么做网站跳转
  • 个人盈利网站怎么建立网站建设 深圳 凡科
  • 网站后台登录地址滨州论坛网站建设
  • 怎么给钓鱼网站做防红wordpress插件合集
  • 骆驼网站建设is_category wordpress
  • 网站中链接怎么做的怎么做资源网站
  • 石家庄建站模板搭建cdr做网站分辨率
  • 学校网站建设有限公司长春网站设计策划书
  • 大连网站建设流程图龙信建设集团网站
  • 徐州好点的做网站的公司深圳做商城网站建设
  • 上海龙象建设集团公司网站网站浮动咨询代码
  • 网站制作培训学校手机网站可以做动态吗
  • 企业推广网站网站开发页面怎么进
  • 嘉兴平湖网站建设网站的底部导航栏怎么做
  • 景安 怎么把网站做别名山东新华电脑学院学网站开发
  • 网站开发好还是app好wordpress 禁用修订
  • win7云主机怎么做网站贵州建设监理网站培训通知栏
  • 制作网站免费建站成都设计公司deanzhang
  • 10个网站用户体验优化的研究结果免费图片设计
  • 做明星网站打广告新闻20条摘抄大全
  • 佛山提供网站设计方案公司wordpress 2.0漏洞
  • wordpress建站教程视频教程百度推广登录首页
  • dede织梦php文章图片网站源码 完整后台 带在线音乐做企业网站进行推广要多少钱
  • 网站正在建设中手机版基于wordpress论文
  • 建设培训网站查询战网
  • 正能量网站下载做网站沧州
  • 网站维护需要什么技能wordpress博客评论删除
  • 行业网站设计师招聘广州番禺网站建设公司推荐
  • 正规网站模板设计软件工程学科评估