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

做网站用什么数据库好用最贵网站建设多少钱

做网站用什么数据库好用,最贵网站建设多少钱,陕西建设部网站,重庆夹夹虫网络公司网站建设文章目录 1. 前言2. 背景3. 为什么要有 ACCESS_ONCE() #xff1f;4. ACCESS_ONCE() 代码实现5. ACCESS_ONCE() 实例分析6. ACCESS() 的演进7. 结语8. 参考资料 1. 前言 限于作者能力水平#xff0c;本文可能存在谬误#xff0c;因此而给读者带来的损失#xff0c;作者不做… 文章目录 1. 前言2. 背景3. 为什么要有 ACCESS_ONCE() 4. ACCESS_ONCE() 代码实现5. ACCESS_ONCE() 实例分析6. ACCESS() 的演进7. 结语8. 参考资料 1. 前言 限于作者能力水平本文可能存在谬误因此而给读者带来的损失作者不做任何承诺。 2. 背景 本文基于 LWN 文章 ACCESS_ONCE() ACCESS_ONCE() and compiler bugs 以及其它相关资料文档经笔者理解后整理而成。本文并非对原文一对一的翻译这一点提请读者注意。 3. 为什么要有 ACCESS_ONCE() 即使是内核源代码的普通读者最终也可能会遇到对 ACCESS_ONCE() 宏的调用。我们可能不会停下来理解这个宏的含义但事实表明很多内核开发者都可能对它的作用没有明确的概念。本文试图解释它为什么存在以及何时必须使用它。你可能想知道为什么这很重要归根结底如果没有明确的告知C 编译器将假定它正在编译的程序的地址空间中只有一个执行线程。并发性不是内置在 C 语言本身因此处理并发访问的机制必须建立在语言之上ACCESS_ONCE() 就是这样一种处理并发访问的机制之一。 这个宏的功能实际上从它的名字中得到了很好的描述其目的是确保生成的代码精确访问一次作为参数传递给它的变量的值即不是从寄存器或缓存等其它地方访问变量的副本而是从变量所在内存地址直接访问一如接下来的 volatile 相关描述。 在说到为什么要有 ACCESS_ONCE() 之前得先说说 volatile 这个变量修饰符。如果我们将某个变量加上 volatile 修饰如 volatile int variable; 将指示编译器总是从内存读取变量的值而不是用之前某个时刻预先读到寄存器的值。这意味一旦给变量加上了 volatile 修饰符这种总是从内存读取变量的值的操作就会伴随变量的整个生存周期。但这对于我们的程序来说并不一定总是正确的可能程序只要求变量在某个特定上下文(如代码临界区)时需要从内存读取变量的值这时候可以去掉变量声明中的 volatile 修饰符接前面的例子变量的定义变成 int variable; 然后在需要的地方通过 ACCESS_ONCE() 访问变量ACCESS_ONCE() 临时加上 volatile 保证从内存读取变量的值类似这样 temp *(volatile int *)variable; 而在其它地方我们正常访问变量(不再通过 ACCESS_ONCE() 访问)类似这样 temp variable; 这样编译器可以优化代码如将变量读取缓存到寄存器然后再从寄存器读取变量的值以优化访问速度。换句话说volatile 关键字的目的是抑制优化但对于同一个变量我们并非总是要在任何访问它的抑制优化通常只需要在特定上下文抑制对它的访问优化这时候 ACCESS_ONCE() 就应运而生了。 前面提到了 volatileLinux 内核代码只在极少数情形下适用于 volatile 。更多关于 Linux 内核下 volatile 的话题可参考 Linux: 为什么不应该在内核代码中使用 volatile 4. ACCESS_ONCE() 代码实现 /* include/linux/compiler.h *//** Prevent the compiler from merging or refetching accesses. The compiler* is also forbidden from reordering successive instances of ACCESS_ONCE(),* but only when the compiler is aware of some particular ordering. One way* to make the compiler aware of ordering is to put the two invocations of* ACCESS_ONCE() in different C statements.** ACCESS_ONCE will only work on scalar types. For union types, ACCESS_ONCE* on a union member will work as long as the size of the member matches the* size of the union and the size is smaller than word size.** The major use cases of ACCESS_ONCE used to be (1) Mediating communication* between process-level code and irq/NMI handlers, all running on the same CPU,* and (2) Ensuring that the compiler does not fold, spindle, or otherwise* mutilate accesses that either do not require ordering or that interact* with an explicit memory barrier or atomic instruction that provides the* required ordering.** If possible use READ_ONCE()/WRITE_ONCE() instead.*/ #define __ACCESS_ONCE(x) ({ \__maybe_unused typeof(x) __var (__force typeof(x)) 0; \(volatile typeof(x) *)(x); }) #define ACCESS_ONCE(x) (*__ACCESS_ONCE(x)) 从代码我们了解到ACCESS_ONCE() 的工作原理是将相关变量暂时转换为 volatile 类型。考虑到优化编译器带来的各种问题对数据的大多数并发访问都受到或肯定应该受到锁的保护。自旋锁和互斥锁都充当优化屏障也就是说它们可以防止屏障一侧的优化延续到另一侧。如果代码只访问锁保护的共享变量并且该变量只能在释放锁并由不同的线程持有时更改则编译器不会产生细微的问题。只有在没有锁或显式屏障编译屏障、内存屏障或等同事物的情况下访问共享数据的地方才需要使用 ACCESS_ONCE()。 5. ACCESS_ONCE() 实例分析 例如考虑 kernel/mutex.c 中的以下代码片段 for (;;) {struct task_struct *owner;owner ACCESS_ONCE(lock-owner);if (owner !mutex_spin_on_owner(lock, owner))break;/* ... */ 这段代码的意图是希望在当前所有者 lock-owner 放弃互斥锁时快速获取互斥锁而无需进入睡眠状态。编译器开发人员可能会热衷于优化所有代码逻辑对于上面代码片段他们可能得出这样的结论由于上述代码片段没有修改 lock-owner因此没有必要每次都通过循环实际获取其值。然后编译器可能会将代码重新排列为如下内容 owner ACCESS_ONCE(lock-owner); for (;;) {if (owner !mutex_spin_on_owner(lock, owner))break; 编译器没考虑到的是 lock-owner 可能正在被另一个执行线程更改结果是代码在多次执行循环时无法知道任何此类更改从而导致令人不快的结果。ACCESS_ONCE() 调用可防止此优化发生使用 ACCESS_ONCE() 后代码将按预期执行。 6. ACCESS() 的演进 由于 ACCESS_ONCE() 依赖于编译器的实现ACCESS_ONCE() 要能正常工作所使用的编译器必须按 ACCESS_ONCE() 所期望的那样工作。世事无常有时候总是事与愿违。早期的 ACCESS_ONCE() 实现如下 #define ACCESS_ONCE(x) (*(volatile typeof(x) *)(x)) 在这个实现版本下Christian Borntraeger 报告了这样一个 ACCESS_ONCE() 相关的问题compiler bug gcc4.6/4.7 with ACCESS_ONCE and workarounds 。简单来说就是 Christian Borntraeger 在 GCC 4.6/4.7 上发现ACCESS_ONCE() 在 union 类型上无法正常工作Christian Borntraeger 和 Linus 讨论能否通过一种 workaround 方式来绕过这个问题。 简而言之就是 ACCESS_ONCE() 强制将变量视为 volatile 类型即使它就像内核中的几乎所有变量一样不是这样声明的。Christian Borntraeger 报告的问题是如果传入 GCC 4.6 和 4.7 的变量不是标量类型则 GCC 4.6 和 4.7 将删除 volatile 修饰符。例如如果 x 是 int则工作正常但如果 x 具有更复杂的类型则不能正常工作。例如ACCESS_ONCE() 通常与页表项一起使用页表项被定义为具有 pte_t 类型 typedef struct {unsigned long pte; } pte_t; 在这种情况下volatile 的语义将在 bug 编译器中丢失从而导致内核 bug 。Christian Borntraeger 开始寻找解决问题的方法却被告知正常的内核实践是尽可能避免绕过编译器错误相反有缺陷的版本应该简单地在内核构建系统中被列入黑名单。但是 GCC 4.6 和 4.7 安装在很多系统上将它们列入黑名单会给许多用户带来不便。而且正如 Linus 所说除了列入黑名单之外还有其他方法。一种方法是修改对 ACCESS_ONCE() 调用以指向相关非标量类型的标量部分。因此如果原始的执行如下作 pte_t p ACCESS_ONCE(pte); 我们可以按如下修改通过直接访问基础标量类型的方式以绕过 GCC 4.6 和 4.7 的 bug unsigned long p ACCESS_ONCE(pte-pte); 但是这种的更改需要审核所有 ACCESS_ONCE() 调用以查找使用非标量类型的调用这将是一个漫长且容易出错的过程。 Christian Borntraeger 探索的另一种方法是删除一些有问题的 ACCESS_ONCE() 调用然后通过 barrier() 放入编译器屏障进行替代。在许多情况下放入编译器屏障就足够了但在其他情况下则不然。同样这需要进行详细的审计并且没有什么可以阻止新代码添加错误的 ACCESS_ONCE() 调用。因此Christian Borntraeger走上了改变 ACCESS_ONCE() 的道路简单地禁止使用非标量类型。最终ACCESS_ONCE() 演变成如下所示版本 #define __ACCESS_ONCE(x) ({ \__maybe_unused typeof(x) __var 0; \(volatile typeof(x) *)(x); }) #define ACCESS_ONCE(x) (*__ACCESS_ONCE(x)) 如果将非标量类型传递到宏中则此版本将导致编译失败。但是需要使用非标量类型的情况呢对于这些情况Christian Borntraeger 引入了 2 个新的宏READ_ONCE() 和 ASSIGN_ONCE() 。前者的定义如下 static __always_inline void __read_once_size(volatile void *p, void *res, int size) {switch (size) {case 1: *(u8 *)res *(volatile u8 *)p; break;case 2: *(u16 *)res *(volatile u16 *)p; break;case 4: *(u32 *)res *(volatile u32 *)p; break; #ifdef CONFIG_64BITcase 8: *(u64 *)res *(volatile u64 *)p; break; #endif} }#define READ_ONCE(p) \({ typeof(p) __val; __read_once_size(p, __val, sizeof(__val)); __val; }) 从本质上讲READ_ONCE() 是通过将变量强制使用标量类型来工作即使传入的变量没有这样的类型。事实上最新的 READ_ONCE() 版本已经可以处理标量类型且包含了更多的 Linux 内核赋予的语义 #define __READ_ONCE_SIZE \ ({ \switch (size) { \case 1: *(__u8 *)res *(volatile __u8 *)p; break; \case 2: *(__u16 *)res *(volatile __u16 *)p; break; \case 4: *(__u32 *)res *(volatile __u32 *)p; break; \case 8: *(__u64 *)res *(volatile __u64 *)p; break; \default: /* 处理非标量类型 */ \barrier(); \__builtin_memcpy((void *)res, (const void *)p, size); \barrier(); \} \ })static __always_inline void __read_once_size(const volatile void *p, void *res, int size) {__READ_ONCE_SIZE; } 更多关于 READ_ONCE() 的实现将在另外的文章里介绍。另外ASSIGN_ONCE() 已经不再存在我们就不再考古了。 7. 结语 大多数人可能对编译器的工作过程都不会很了解在这些依赖编译器实现的场合如果我们无法确定编译器的编译结果那么查看编译结果的反汇编代码将是一个不错的选择。 8. 参考资料 [1] https://lwn.net/Articles/508991/ [2] https://lwn.net/Articles/624126/
http://www.w-s-a.com/news/300813/

相关文章:

  • 保定清苑住房和城乡建设局网站分类信息网站程序
  • 可以做视频推广的网站选择大连网站建设
  • 在线网站开发网站在哪里
  • 建站的步骤上海快速优化排名
  • 招聘网站做一下要多少钱网站设计公司 国际
  • 巩义专业网站建设公司首选seo研究院
  • 大流量网站解决访问量友情链接如何添加
  • 教育网站建设网永康市住房和城乡建设局网站
  • 阿里巴巴官网网站django 做网站的代码
  • 网站建设 军报wordpress 订餐模板
  • 网站虚拟主机 会计处理石家庄站建设费用多少
  • 网站建设 服务内容 费用简述网站开发流程
  • 公司制作网站跟企业文化的关系空间制作网站
  • 浙江建设监理协会网站个人网站设计规划书
  • wordpress太卡了贵州seo推广
  • 企业介绍微网站怎么做的手机软件商城免费下载
  • 新手网站设计定价网站开发销售
  • 网站开发公司oa有没有找人做标书的网站
  • 传统门户网站有哪些人武部正规化建设
  • 台州网站制作方案免费无代码开发平台
  • 精通网站建设 pdf微盘学做电商的步骤
  • 想在网上做设计接单有没有网站找一个免费域名的网站
  • 湘潭市网站建设科技有限公司杭州网站建设(推荐乐云践新)
  • 优秀网站评析西双版纳傣族自治州民宿
  • 常用的cms建站系统c2c网站模板
  • wordpress更换图标seo网站建设公司
  • 网站备案 深圳小程序怎么进入公众号
  • 实名认证域名可以做电影网站吗坪山网站设计的公司
  • wdcp怎么上传做好的网站管理咨询公司名称参考
  • 设计师网站pin分销系统小程序开发